mirror of
https://github.com/therealKyp/Earth-and-Beyond-server
synced 2026-08-13 22:23:03 -04:00
7358 lines
206 KiB
C++
7358 lines
206 KiB
C++
// ClientToSectorServer.cpp
|
|
|
|
/***********************************************
|
|
* /////////////////////////////////////// *
|
|
* // CLIENT TO SECTOR SERVER OPCODES // *
|
|
* /////////////////////////////////////// *
|
|
***********************************************/
|
|
|
|
#include "Net7.h"
|
|
#include "Connection.h"
|
|
#include "ServerManager.h"
|
|
#include "Opcodes.h"
|
|
#include "PlayerClass.h"
|
|
|
|
void Connection::ProcessProxyClientOpcode(short opcode, short bytes)
|
|
{
|
|
switch (opcode)
|
|
{
|
|
case ENB_OPCODE_3002_TCP_LOGIN_VALIDATE:
|
|
ValidateLoginLink();
|
|
break;
|
|
|
|
case ENB_OPCODE_3004_PLAYER_SHIP_SENT:
|
|
CommenceNavSend(); //shut down connection and cancel out TCP link
|
|
break;
|
|
|
|
case ENB_OPCODE_3003_TCP_LOGIN_CLOSE:
|
|
LogMessage("--> Shutdown login link\n");
|
|
ShutdownLoginLink();
|
|
break;
|
|
|
|
case ENB_OPCODE_3006_PLAYER_LOGIN_FAILED:
|
|
LogMessage("LOGIN FAILURE! Resend handoff\n");
|
|
HandleLoginFailed();
|
|
break;
|
|
|
|
case ENB_OPCODE_3008_STARBASE_LOGIN_COMPLETE:
|
|
HandleStarbaseLoginComplete();
|
|
break;
|
|
|
|
default :
|
|
ProxyClientOpcode(opcode, bytes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Connection::ValidateLoginLink()
|
|
{
|
|
long player_id = *((long*) m_RecvBuffer);
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(player_id);
|
|
|
|
m_AvatarID = player_id;
|
|
|
|
if (p)
|
|
{
|
|
LogMessage("Validating login link for player '%s'\n", p->Name());
|
|
p->SetTCPLoginLink(this);
|
|
m_LastOwner = p->Name();
|
|
}
|
|
}
|
|
|
|
void Connection::ShutdownLoginLink()
|
|
{
|
|
long player_id = *((long*) m_RecvBuffer);
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(player_id);
|
|
|
|
if (p && m_AvatarID == player_id)
|
|
{
|
|
LogMessage("* Terminating Login link for '%s'\n", p->Name());
|
|
p->SetTCPLoginLink(0);
|
|
m_AvatarID = 0;
|
|
m_TcpThreadRunning = false;
|
|
}
|
|
}
|
|
|
|
void Connection::ShutdownTCPLink(long game_id)
|
|
{
|
|
if (m_AvatarID == game_id)
|
|
{
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(game_id);
|
|
LogMessage("Terminating TCP link for '%s'\n", p->Name());
|
|
//first clear any remaining messages
|
|
#ifdef WIN32
|
|
if (m_TcpThreadRunning)
|
|
{
|
|
ResumeThread(m_RecvThreadHandle);
|
|
}
|
|
#endif
|
|
Sleep(100);
|
|
p->SetTCPLoginLink(0);
|
|
m_AvatarID = 0;
|
|
m_TcpThreadRunning = false;
|
|
}
|
|
}
|
|
|
|
void Connection::ProxyClientOpcode(short opcode, short bytes)
|
|
{
|
|
Player *p;
|
|
|
|
p = g_ServerMgr->m_PlayerMgr.GetPlayer(m_AvatarID);
|
|
|
|
if (p)
|
|
{
|
|
p->AddMessage(opcode, bytes, m_RecvBuffer);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleStarbaseLoginComplete()
|
|
{
|
|
long player_id = *((long*) m_RecvBuffer);
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(player_id);
|
|
|
|
if (p && m_AvatarID == player_id)
|
|
{
|
|
if (p->PlayerIndex()->GetSectorNum() > 9999)
|
|
{
|
|
LogMessage("Starbase Login complete for '%s' Retaining TCP Link\n", p->Name());
|
|
}
|
|
else
|
|
{
|
|
LogMessage("Sector Login complete for '%s' Retaining TCP Link\n", p->Name());
|
|
p->FinishLogin();
|
|
}
|
|
p->SetNavCommence();
|
|
}
|
|
}
|
|
|
|
void Connection::CommenceNavSend()
|
|
{
|
|
long player_id = *((long*) m_RecvBuffer);
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(player_id);
|
|
|
|
if (p && m_AvatarID == player_id)
|
|
{
|
|
LogMessage("Terminating Login link for '%s'\n", p->Name());
|
|
p->SetTCPLoginLink(0);
|
|
p->SetNavCommence();
|
|
m_AvatarID = 0;
|
|
m_TcpThreadRunning = false;
|
|
p->FinishLogin();
|
|
}
|
|
}
|
|
|
|
void Connection::HandleLoginFailed()
|
|
{
|
|
long player_id = *((long*) m_RecvBuffer);
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(player_id);
|
|
|
|
if (p)
|
|
{
|
|
long sector_id = p->PlayerIndex()->GetSectorNum();
|
|
if (sector_id > 0)
|
|
{
|
|
LogMessage("Handle login fail for %s\n", p->Name());
|
|
//p->SetActive(false);
|
|
//g_PlayerMgr->DropPlayerFromSector(p);
|
|
g_ServerMgr->GetSectorManager(sector_id)->SectorServerHandoff(p, sector_id);
|
|
//p->SendOpcode(ENB_OPCODE_3006_PLAYER_LOGIN_FAILED_CONFIRM, 0, 0);
|
|
//LogMessage("Login fail confirm - resend handoff for %s.\n", p->Name());
|
|
p->LoginFailed();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
#include "Net7.h"
|
|
#include "Connection.h"
|
|
#include "ServerManager.h"
|
|
#include "Opcodes.h"
|
|
#include "PacketStructures.h"
|
|
#include "ObjectClass.h"
|
|
#include "ObjectManager.h"
|
|
|
|
void Connection::SendAdvancedPositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
char packet[sizeof(AdvancedPositionalUpdate)];
|
|
memset(packet, 0, sizeof(packet));
|
|
short *pBitmask = (short *) &packet[0];
|
|
long *pLong = (long *) &packet[2];
|
|
float *pFloat = (float *) &packet[2];
|
|
short bitmask = position_info->Bitmask;
|
|
int index = 0;
|
|
|
|
// Package the data into the packet
|
|
*pBitmask = bitmask;
|
|
pLong[index++] = object_id; // GameID
|
|
pLong[index++] = GetNet7TickCount(); // TimeStamp
|
|
pFloat[index++] = position_info->Position[0];
|
|
pFloat[index++] = position_info->Position[1];
|
|
pFloat[index++] = position_info->Position[2];
|
|
pFloat[index++] = position_info->Orientation[0];
|
|
pFloat[index++] = position_info->Orientation[1];
|
|
pFloat[index++] = position_info->Orientation[2];
|
|
pFloat[index++] = position_info->Orientation[3];
|
|
pLong[index++] = position_info->MovementID;
|
|
if (bitmask & 0x0001)
|
|
{
|
|
pFloat[index++] = position_info->CurrentSpeed;
|
|
}
|
|
if (bitmask & 0x0002)
|
|
{
|
|
pFloat[index++] = position_info->SetSpeed;
|
|
}
|
|
if (bitmask & 0x0004)
|
|
{
|
|
pFloat[index++] = position_info->Acceleration;
|
|
}
|
|
if (bitmask & 0x0008)
|
|
{
|
|
pFloat[index++] = position_info->RotY;
|
|
}
|
|
if (bitmask & 0x0010)
|
|
{
|
|
pFloat[index++] = position_info->DesiredY;
|
|
}
|
|
if (bitmask & 0x0020)
|
|
{
|
|
pFloat[index++] = position_info->RotZ;
|
|
}
|
|
if (bitmask & 0x0040)
|
|
{
|
|
pFloat[index++] = position_info->DesiredZ;
|
|
}
|
|
if (bitmask & 0x0080)
|
|
{
|
|
pFloat[index++] = position_info->ImpartedVelocity[0];
|
|
pFloat[index++] = position_info->ImpartedVelocity[1];
|
|
pFloat[index++] = position_info->ImpartedVelocity[2];
|
|
pFloat[index++] = position_info->ImpartedSpin;
|
|
pFloat[index++] = position_info->ImpartedRoll;
|
|
pFloat[index++] = position_info->ImpartedPitch;
|
|
}
|
|
if (bitmask & 0x0100)
|
|
{
|
|
pLong[index++] = position_info->UpdatePeriod;
|
|
}
|
|
|
|
//LogMessage("Sending AdvancedPositionalUpdate packet\n");
|
|
int length = 2 + 4 * index;
|
|
SendResponse(ENB_OPCODE_003E_ADVANCED_POSITIONAL_UPDATE, (unsigned char *) &packet, length);
|
|
}
|
|
|
|
void Connection::SendRelationship(long ObjectID, long Reaction, bool IsAttacking)
|
|
{
|
|
Relationship response;
|
|
response.ObjectID = ntohl(ObjectID);
|
|
response.Reaction = Reaction;
|
|
response.IsAttacking = IsAttacking ? 1 : 0;
|
|
|
|
//LogMessage("Sending Relationship packet\n");
|
|
SendResponse(ENB_OPCODE_0089_RELATIONSHIP, (unsigned char *) &response, sizeof(response));
|
|
}
|
|
|
|
void Connection::SendNameDecal(int game_id, char *shipname, float h, float s, float v)
|
|
{
|
|
NameDecal name_decal;
|
|
|
|
memset(&name_decal, 0, sizeof(name_decal));
|
|
name_decal.GameID = game_id;
|
|
name_decal.RGB[0] = h;
|
|
name_decal.RGB[1] = s;
|
|
name_decal.RGB[2] = v;
|
|
strncpy(name_decal.Name, shipname, sizeof(name_decal.Name) - 1);
|
|
|
|
//LogMessage("Sending NameDecal packet\n");
|
|
SendResponse(ENB_OPCODE_00B2_NAME_DECAL, (unsigned char *) &name_decal, sizeof(name_decal));
|
|
}
|
|
|
|
void Connection::SendDecal(int game_id, int decal_id, int decal_count)
|
|
{
|
|
if (decal_count > MAX_DECALS)
|
|
{
|
|
decal_count = MAX_DECALS;
|
|
}
|
|
|
|
Decal decal;
|
|
decal.GameID = game_id;
|
|
decal.DecalCount = decal_count;
|
|
for (int i = 0; i < decal_count; i++)
|
|
{
|
|
decal.Item[i].Index = i + 1;
|
|
decal.Item[i].HSV[0] = 1.0;
|
|
decal.Item[i].HSV[1] = 1.0;
|
|
decal.Item[i].HSV[2] = 1.0;
|
|
decal.Item[i].opacity = 1.0;
|
|
}
|
|
|
|
size_t size = ((char *) &decal.Item[decal_count]) - ((char *) &decal);
|
|
|
|
//LogMessage("Sending Decal packet\n");
|
|
SendResponse(ENB_OPCODE_0010_DECAL, (unsigned char *) &decal, size);
|
|
}
|
|
|
|
void Connection::SendCreate(int game_id, float scale, short asset, int type, float h, float s, float v)
|
|
{
|
|
Create create;
|
|
create.GameID = game_id;
|
|
create.Scale = scale;
|
|
create.BaseAsset = asset;
|
|
create.Type = (char) type;
|
|
create.HSV[0] = h;
|
|
create.HSV[1] = s;
|
|
create.HSV[2] = v;
|
|
|
|
//LogMessage("Sending Create packet\n");
|
|
SendResponse(ENB_OPCODE_0004_CREATE, (unsigned char *) &create, sizeof(create));
|
|
}
|
|
|
|
void Connection::SendStart(long start_id)
|
|
{
|
|
//LogMessage("Sending Start packet\n");
|
|
SendResponse(ENB_OPCODE_0005_START, (unsigned char *) &start_id, sizeof(start_id));
|
|
}
|
|
|
|
void Connection::SendDataFileToClient(char *filename, long avatar_id)
|
|
{
|
|
char old_path[MAX_PATH];
|
|
GetCurrentDirectory(sizeof(old_path), old_path);
|
|
SetCurrentDirectory(SERVER_DATABASE_PATH);
|
|
FILE *f = fopen(filename, "rb");
|
|
if (f)
|
|
{
|
|
fseek(f,0,SEEK_END);
|
|
long length = ftell(f);
|
|
if ((length > 0) && (length < TCP_BUFFER_SIZE))
|
|
{
|
|
LogMessage("Sending data file '%s'\n", filename);
|
|
fseek(f,0,SEEK_SET);
|
|
unsigned char * buffer = new unsigned char[length];
|
|
fread(buffer, 1, length, f);
|
|
if (avatar_id)
|
|
{
|
|
*((long *) &buffer[4]) = avatar_id;
|
|
}
|
|
m_CryptOut.RC4(buffer, length);
|
|
Send(buffer, length);
|
|
delete [] buffer;
|
|
}
|
|
else
|
|
{
|
|
LogMessage("SendDataFileToClient: Invalid file length %d : '%s'\n", length, filename);
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
{
|
|
LogMessage("SendDataFileToClient: Unable to open %s\n", filename);
|
|
}
|
|
|
|
SetCurrentDirectory(old_path);
|
|
}
|
|
|
|
void Connection::SendClientType(long client_type)
|
|
{
|
|
//LogMessage("Sending ClientType packet\n");
|
|
SendResponse(ENB_OPCODE_003C_CLIENT_TYPE, (unsigned char *) &client_type, sizeof(client_type));
|
|
}
|
|
|
|
void Connection::SendGalaxyMap(char *system, char *sector, char *station)
|
|
{
|
|
struct GalaxyMap
|
|
{
|
|
long Type;
|
|
long Size;
|
|
long PlayerID;
|
|
char Variable[64];
|
|
long unknown;
|
|
};
|
|
|
|
GalaxyMap galaxy_map;
|
|
long string_length;
|
|
long size = 8; // include PlayerID and unknown
|
|
char *p = galaxy_map.Variable;
|
|
|
|
galaxy_map.Type = 4;
|
|
galaxy_map.PlayerID = m_AvatarID;
|
|
|
|
// System
|
|
strcpy(p, system);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
// Sector
|
|
strcpy(p, sector);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
// Station
|
|
strcpy(p, station);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
*((long *) p) = 375; // unknown = 375
|
|
galaxy_map.Size = size;
|
|
|
|
//LogMessage("Sending GalaxyMap packet\n");
|
|
SendResponse(ENB_OPCODE_0097_GALAXY_MAP, (unsigned char * ) &galaxy_map, size + 8);
|
|
}
|
|
|
|
void Connection::SendStarbaseSet(char action, char exit_mode, long sector_id)
|
|
{
|
|
StarbaseSet starbase_set;
|
|
memset(&starbase_set, 0, sizeof(starbase_set));
|
|
starbase_set.StarbaseID = sector_id;
|
|
starbase_set.Action = action;
|
|
starbase_set.ExitMode = exit_mode;
|
|
|
|
SendResponse(ENB_OPCODE_004F_STARBASE_SET, (unsigned char *) &starbase_set, sizeof(starbase_set));
|
|
}
|
|
|
|
void Connection::SendConstantPositionalUpdate(long game_id, float x, float y, float z, float *orientation)
|
|
{
|
|
ConstantPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = game_id;
|
|
update.Position[0] = x;
|
|
update.Position[1] = y;
|
|
update.Position[2] = z;
|
|
if (orientation)
|
|
{
|
|
update.Orientation[0] = orientation[0];
|
|
update.Orientation[1] = orientation[1];
|
|
update.Orientation[2] = orientation[2];
|
|
update.Orientation[3] = orientation[3];
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_0040_CONSTANT_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SetManufactureID(long mfg_id)
|
|
{
|
|
SendResponse(ENB_OPCODE_007F_MANUFACTURE_SET_MANUFACTURE_ID, (unsigned char *) &mfg_id, sizeof(mfg_id));
|
|
}
|
|
|
|
void Connection::SendActivateRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
SendResponse(ENB_OPCODE_0030_ACTIVATE_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Connection::SendActivateNextRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
SendResponse(ENB_OPCODE_0031_ACTIVATE_NEXT_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Connection::SendSimplePositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
SimplePositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = object_id;
|
|
update.TimeStamp = GetNet7TickCount();
|
|
update.Position[0] = position_info->Position[0];
|
|
update.Position[1] = position_info->Position[1];
|
|
update.Position[2] = position_info->Position[2];
|
|
update.Orientation[0] = position_info->Orientation[0];
|
|
update.Orientation[1] = position_info->Orientation[1];
|
|
update.Orientation[2] = position_info->Orientation[2];
|
|
update.Orientation[3] = position_info->Orientation[3];
|
|
update.Velocity[0] = position_info->Velocity[0];
|
|
update.Velocity[1] = position_info->Velocity[1];
|
|
update.Velocity[2] = position_info->Velocity[2];
|
|
|
|
//LogMessage("Sending SimplePositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_0008_SIMPLE_POSITIONAL_UDPATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendPlanetPositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
PlanetPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = object_id;
|
|
update.TimeStamp = GetNet7TickCount();
|
|
update.Position[0] = position_info->Position[0];
|
|
update.Position[1] = position_info->Position[1];
|
|
update.Position[2] = position_info->Position[2];
|
|
update.OrbitID = position_info->OrbitID;
|
|
update.OrbitDist = position_info->OrbitDist;
|
|
update.OrbitAngle = position_info->OrbitAngle;
|
|
update.OrbitRate = position_info->OrbitRate;
|
|
update.RotateAngle = position_info->RotateAngle;
|
|
update.RotateRate = position_info->RotateRate;
|
|
update.TiltAngle = position_info->TiltAngle;
|
|
|
|
//LogMessage("Sending PlanetPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_003F_PLANET_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendResourceName(long resourceID, char *resource_name)
|
|
{
|
|
unsigned char aux_data[64];
|
|
memset(aux_data, 0, 64);
|
|
short length = strlen(resource_name);
|
|
*((long *) aux_data) = resourceID;
|
|
*((short *) &aux_data[4]) = length + 4;
|
|
*((short *) &aux_data[6]) = 0x1201;
|
|
*((short *) &aux_data[8]) = length;
|
|
|
|
strncpy((char*)&aux_data[10], resource_name, length);
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, length+10);
|
|
}
|
|
|
|
void Connection::SendAuxNameSignature(Object *obj)
|
|
{
|
|
char *name = "d";
|
|
if (obj->IsNav())
|
|
{
|
|
name = obj->Name();
|
|
}
|
|
|
|
int length = strlen(name) + 15;
|
|
char *packet = (char*)_alloca(length);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = strlen(name) + 9;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x72;
|
|
*((short *) &packet[8]) = strlen(name);
|
|
strncpy(&packet[10], name, strlen(name));
|
|
int i = 10 + strlen(name);
|
|
packet[i++] = obj->IsNav();
|
|
*((float *) &packet[i]) = obj->Signature();
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length);
|
|
}
|
|
|
|
void Connection::SendSimpleAuxName(Object *obj)
|
|
{
|
|
int length = strlen(obj->Name()) + 10;
|
|
char *packet = (char*)_alloca(length);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = strlen(obj->Name()) + 4;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x12;
|
|
*((short *) &packet[8]) = strlen(obj->Name());
|
|
strncpy(&packet[10], obj->Name(), strlen(obj->Name()));
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length);
|
|
}
|
|
|
|
void Connection::SendNavigation(int game_id, float signature, char visited, int nav_type, char is_huge)
|
|
{
|
|
Navigation navigation;
|
|
navigation.GameID = game_id;
|
|
navigation.Signature = signature;
|
|
navigation.PlayerHasVisited = visited;
|
|
navigation.NavType = nav_type;
|
|
navigation.IsHuge = is_huge;
|
|
|
|
//LogMessage("Sending Navigation packet\n");
|
|
SendResponse(ENB_OPCODE_0099_NAVIGATION, (unsigned char *) &navigation, sizeof(navigation));
|
|
}
|
|
|
|
void Connection::SendClientSetTime(long TimeSent)
|
|
{
|
|
ClientSetTime data;
|
|
data.ClientSent = TimeSent;
|
|
data.ServerReceived = GetNet7TickCount();
|
|
data.ServerSent = data.ServerReceived;
|
|
|
|
SendResponse(ENB_OPCODE_0034_CLIENT_SET_TIME, (unsigned char *) &data, sizeof(data));
|
|
|
|
//LogMessage("Sending SetClientTime packet 0x%08x\n",TimeSent);
|
|
}
|
|
|
|
void Connection::SendMessageString(char *msg, char color, bool log)
|
|
{
|
|
char buffer[512];
|
|
memset(buffer, 0, sizeof(buffer));
|
|
short length = strlen(msg) + 1;
|
|
*((short *) &buffer[0]) = length;
|
|
buffer[2] = color;
|
|
strcpy(&buffer[3], msg);
|
|
|
|
SendResponse(ENB_OPCODE_001D_MESSAGE_STRING, (unsigned char *) buffer, length + 3);
|
|
}
|
|
|
|
//#if 0
|
|
|
|
#include "Net7.h"
|
|
#include "Connection.h"
|
|
#include "ServerManager.h"
|
|
#include "Opcodes.h"
|
|
#include "PacketStructures.h"
|
|
#include "SectorData.h"
|
|
#include "VectorMath.h"
|
|
#include "UDPConnection.h"
|
|
#include "StationLoader.h"
|
|
#include "ObjectClass.h"
|
|
#include "ObjectManager.h"
|
|
#include <string>
|
|
#include "MOBclass.h"
|
|
#include "PacketMethods.h"
|
|
|
|
static int _httoi(const char *value); //convert hex string to int
|
|
|
|
int SkillPointsLevel;
|
|
|
|
void Connection::ProcessSectorServerOpcode(short opcode, short bytes)
|
|
{
|
|
if (!m_ServerMgr.IsSectorServerReady(m_TcpPort))
|
|
{
|
|
// Handle MASTER SERVER to SECTOR SERVER packets
|
|
HandleWaitingForMasterServer(opcode, bytes);
|
|
}
|
|
else
|
|
{
|
|
// Handle CLIENT to SECTOR SERVER packets
|
|
HandleClientOpcode(opcode, bytes);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleWaitingForMasterServer(short opcode, short bytes)
|
|
{
|
|
bool success = false;
|
|
// Until the Sector Server gets an incoming connection from the
|
|
// Master Server, we will ignore connections from any clients.
|
|
switch (opcode)
|
|
{
|
|
case ENB_OPCODE_7801_SECTOR_ASSIGNMENT :
|
|
if (bytes == 4)
|
|
{
|
|
m_SectorID = *((long *) m_RecvBuffer);
|
|
//LogMessage("Received Sector Assignment - SectorID=%d\n", m_SectorID);
|
|
|
|
if (m_ServerMgr.SetupSectorServer(m_SectorID))
|
|
{
|
|
// This is no longer a Client to Sector Server connection
|
|
// This is now a Master Server to Sector Server connection
|
|
m_ServerType = CONNECTION_TYPE_MASTER_SERVER_TO_SECTOR_SERVER;
|
|
m_ServerMgr.SetSectorServerReady(m_TcpPort, true);
|
|
LogMessage("Port:%d Sector:%d `%s`\n",
|
|
m_TcpPort, m_SectorID, g_ServerMgr->GetSectorName(m_SectorID));
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
LogMessage("ERROR: m_ServerMgr.SetupSectorServer failed\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogMessage("ERROR: opcode 0x7801 is not four bytes!\n");
|
|
}
|
|
break;
|
|
|
|
default :
|
|
LogMessage("HandleWaitingForMasterServer -- UNRECOGNIZED OPCODE 0x%04x\n", opcode);
|
|
break;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
// TODO: Kill this connection
|
|
}
|
|
}
|
|
|
|
void Connection::HandleClientOpcode(short opcode, short bytes)
|
|
{
|
|
//LogMessage("HandleClientOpcode -- OPCODE 0x%04x\n", opcode);
|
|
//DumpBuffer(m_RecvBuffer, bytes);
|
|
|
|
switch (opcode)
|
|
{
|
|
case ENB_OPCODE_0002_LOGIN:
|
|
HandleLogin();
|
|
break;
|
|
|
|
case ENB_OPCODE_0006_START_ACK :
|
|
HandleStartAck();
|
|
break;
|
|
|
|
case ENB_OPCODE_0012_TURN:
|
|
HandleTurn();
|
|
break;
|
|
|
|
case ENB_OPCODE_0013_TILT:
|
|
HandleTilt();
|
|
break;
|
|
|
|
case ENB_OPCODE_0014_MOVE :
|
|
HandleMove();
|
|
break;
|
|
|
|
case ENB_OPCODE_0017_REQUEST_TARGET :
|
|
HandleRequestTarget();
|
|
break;
|
|
|
|
case ENB_OPCODE_0018_REQUEST_TARGETS_TARGET :
|
|
HandleRequestTargetsTarget();
|
|
break;
|
|
|
|
case ENB_OPCODE_001A_DEBUG :
|
|
HandleDebug();
|
|
break;
|
|
|
|
case ENB_OPCODE_0027_INVENTORY_MOVE:
|
|
HandleInventoryMove();
|
|
break;
|
|
|
|
case ENB_OPCODE_0029_ITEM_STATE:
|
|
HandleItemState();
|
|
break;
|
|
|
|
case ENB_OPCODE_002C_ACTION :
|
|
case ENB_OPCODE_002D_ACTION2 :
|
|
HandleAction();
|
|
break;
|
|
|
|
case ENB_OPCODE_002E_OPTION :
|
|
HandleOption();
|
|
break;
|
|
|
|
case ENB_OPCODE_0033_CLIENT_CHAT :
|
|
HandleClientChat();
|
|
break;
|
|
|
|
case ENB_OPCODE_0044_REQUEST_TIME :
|
|
HandleRequestTime();
|
|
break;
|
|
|
|
case ENB_OPCODE_004E_STARBASE_REQUEST :
|
|
HandleStarbaseRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_0051_SKILL_STRING_RQ:
|
|
HandleSkillStringRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_0055_SELECT_TALK_TREE :
|
|
HandleSelectTalkTree();
|
|
break;
|
|
|
|
case ENB_OPCODE_0057_SKILL_UP:
|
|
HandleSkillAction();
|
|
break;
|
|
|
|
case ENB_OPCODE_0058_SKILL_ABILITY:
|
|
HandleSkillAbility();
|
|
break;
|
|
|
|
case ENB_OPCODE_005A_VERB_REQUEST:
|
|
HandleVerbRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_005D_EQUIP_USE :
|
|
HandleEquipUse();
|
|
break;
|
|
|
|
case ENB_OPCODE_005E_AVATAR_EMOTE:
|
|
HandleChatStream();
|
|
break;
|
|
|
|
case ENB_OPCODE_0079_MANUFACTURE_ITEM_CATAGORY:
|
|
HandleManufactureTerminal();
|
|
break;
|
|
|
|
case ENB_OPCODE_007A_MANUFACTURE_ITEM_CATAGORY :
|
|
HandleManufactureCategorySelection();
|
|
break;
|
|
|
|
case ENB_OPCODE_007B_MANUFACTURE_ITEM_ID :
|
|
HandleManufactureSetItem();
|
|
break;
|
|
|
|
case ENB_OPCODE_007C_REFINERY_ITEM_ID :
|
|
HandleRefineSetItem();
|
|
break;
|
|
|
|
case ENB_OPCODE_007E_MANUFACTURE_ACTION:
|
|
HandleManufactureAction();
|
|
break;
|
|
|
|
case ENB_OPCODE_0080_MANUFACTURE_TECH_LEVEL_FILTER:
|
|
HandleManufactureLevelFilter();
|
|
break;
|
|
|
|
case ENB_OPCODE_0086_MISSION_FORFEIT:
|
|
HandleMissionForfeit();
|
|
break;
|
|
|
|
case ENB_OPCODE_0087_MISSION_DISMISSAL:
|
|
HandleMissionDismissal();
|
|
break;
|
|
|
|
case ENB_OPCODE_0088_PETITION_STUCK:
|
|
HandlePetitionStuck();
|
|
break;
|
|
|
|
case ENB_OPCODE_008D_INCAPACITANCE_REQUEST:
|
|
HandleIncapacitanceRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_0098_GALAXY_MAP_REQUEST :
|
|
HandleGalaxyMapRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_009B_WARP:
|
|
HandleWarp();
|
|
break;
|
|
|
|
case ENB_OPCODE_009D_STARBASE_AVATAR_CHANGE :
|
|
HandleStarbaseAvatarChange();
|
|
break;
|
|
|
|
case ENB_OPCODE_009F_STARBASE_ROOM_CHANGE :
|
|
HandleStarbaseRoomChange();
|
|
break;
|
|
|
|
case ENB_OPCODE_00A1_TRIGGER_EMOTE :
|
|
HandleTriggerEmote();
|
|
break;
|
|
|
|
case ENB_OPCODE_00A3_CLIENT_CHAT_REQUEST :
|
|
HandleClientChatRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_00B9_LOGOFF_REQUEST :
|
|
HandleLogoffRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_00BC_CTA_REQUEST :
|
|
HandleCTARequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_00C0_CONFIRMED_ACTION_RESPONSE:
|
|
HandleActionResponse();
|
|
break;
|
|
|
|
default :
|
|
LogMessage("HandleClientOpcode -- UNRECOGNIZED OPCODE 0x%04x\n", opcode);
|
|
DumpBuffer(m_RecvBuffer, bytes);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Connection::HandleLogin()
|
|
{
|
|
Login * login = (Login *) m_RecvBuffer;
|
|
|
|
m_MasterJoin = login->join_data;
|
|
|
|
//LogMessage("Sector server received Login packet\n");
|
|
|
|
m_AvatarID = ntohl(m_MasterJoin.avatar_id_lsb);
|
|
m_SectorID = ntohl(m_MasterJoin.ToSectorID);
|
|
m_FromSectorID = ntohl(m_MasterJoin.FromSectorID);
|
|
|
|
// Obtain the sector manager for the specified sector
|
|
m_SectorMgr = m_ServerMgr.GetSectorManager(m_SectorID);
|
|
m_Player = m_ServerMgr.m_PlayerMgr.GetPlayer(m_AvatarID, true);
|
|
|
|
if (!m_SectorMgr)
|
|
{
|
|
LogMessage("HandleLogin: Missing SectorManager for sector %d\n", m_SectorID);
|
|
}
|
|
else if (!m_Player)
|
|
{
|
|
LogMessage("Unable to find player for avatar ID 0x%08x\n",m_AvatarID);
|
|
}
|
|
else
|
|
{
|
|
//set up the player with a pointer to its sector manager and object manager
|
|
m_ObjectMgr = m_SectorMgr->GetObjectManager();
|
|
m_Player->SetObjectManager(m_ObjectMgr);
|
|
m_Player->SetSectorManager(m_SectorMgr);
|
|
|
|
// Add the player to the list of players we are tracking
|
|
// Calls the player's SectorLogin() and FirstLogin() methods
|
|
//m_ServerMgr.m_PlayerMgr.AddPlayer(m_AvatarID, this);
|
|
|
|
// Set the client time
|
|
SendClientSetTime(login->TimeSent);
|
|
LogDebug("Sending server time\n");
|
|
|
|
// Send the sector content to the client - NB AddPlayer must occur before SectorLogin
|
|
m_SectorMgr->HandleSectorLogin(m_Player);
|
|
|
|
m_StarbaseTargetID = 0;
|
|
|
|
m_ActionResponseReceived = false;
|
|
m_Player->SaveData();
|
|
}
|
|
}
|
|
|
|
void Connection::HandleSkillAction()
|
|
{
|
|
SkillAction * Skill = (SkillAction *) m_RecvBuffer;
|
|
//m_Player->HandleSkillAction(Skill);
|
|
}
|
|
|
|
void Connection::HandleSkillAbility()
|
|
{
|
|
SkillUse * Ability = (SkillUse *) m_RecvBuffer;
|
|
//m_Player->HandleSkillAbility(Ability);
|
|
}
|
|
|
|
//------MANUFACTURING
|
|
|
|
// Request Catagorys
|
|
void Connection::HandleManufactureTerminal()
|
|
{
|
|
ManufactureData * Packet = (ManufactureData *) m_RecvBuffer;
|
|
//m_Player->HandleManufactureTerminal(ntohl(Packet->Data));
|
|
}
|
|
|
|
// Called when a catigory is selected
|
|
void Connection::HandleManufactureCategorySelection()
|
|
{
|
|
ManufactureData * Packet = (ManufactureData *) m_RecvBuffer;
|
|
//m_Player->HandleManufactureCategorySelection(ntohl(Packet->Data));
|
|
}
|
|
|
|
// Called when a formula is selected
|
|
void Connection::HandleManufactureSetItem()
|
|
{
|
|
ManufactureData * Packet = (ManufactureData *) m_RecvBuffer;
|
|
//m_Player->HandleManufactureSetItem(ntohl(Packet->Data));
|
|
}
|
|
|
|
void Connection::HandleManufactureLevelFilter()
|
|
{
|
|
ManufactureTechLevelFilter * Filter = (ManufactureTechLevelFilter *) m_RecvBuffer;
|
|
//m_Player->HandleManufactureLevelFilter(Filter->Enable, ntohl(Filter->BitField));
|
|
}
|
|
|
|
// --- Handels cration/dismantel of items
|
|
// Does it 'Handel' Bach as well? Sorry, couldn't resist!
|
|
void Connection::HandleManufactureAction()
|
|
{
|
|
ManufactureData * Packet = (ManufactureData *) m_RecvBuffer;
|
|
//m_Player->HandleManufactureAction(ntohl(Packet->Data));
|
|
}
|
|
|
|
void Connection::HandleRefineSetItem()
|
|
{
|
|
ManufactureData * Packet = (ManufactureData *) m_RecvBuffer;
|
|
//m_Player->HandleRefineSetItem(Packet->Data);
|
|
}
|
|
|
|
//-------------------
|
|
|
|
void Connection::RemovePlayer() //this just signals graphic removal of player from sector
|
|
{
|
|
m_Player->Remove();
|
|
}
|
|
|
|
void Connection::SendStarbaseSet(char action, char exit_mode)
|
|
{
|
|
StarbaseSet starbase_set;
|
|
memset(&starbase_set, 0, sizeof(starbase_set));
|
|
starbase_set.StarbaseID = m_SectorID;
|
|
starbase_set.Action = action;
|
|
starbase_set.ExitMode = exit_mode;
|
|
|
|
//LogMessage("Sending StarbaseSet packet\n");
|
|
SendResponse(ENB_OPCODE_004F_STARBASE_SET, (unsigned char *) &starbase_set, sizeof(starbase_set));
|
|
}
|
|
|
|
long Connection::TryLoungeFile(long sector_id)
|
|
{
|
|
long return_sector = sector_id;
|
|
char old_path[MAX_PATH];
|
|
char lounge_npc[MAX_PATH];
|
|
|
|
sprintf(lounge_npc, "LoungeNPC_%d.dat", sector_id);
|
|
|
|
GetCurrentDirectory(sizeof(old_path), old_path);
|
|
SetCurrentDirectory(SERVER_DATABASE_PATH);
|
|
FILE *f = fopen(lounge_npc, "rb");
|
|
if (!f)
|
|
{
|
|
sector_id = sector_id / 1000;
|
|
//no file exists for this station.
|
|
switch(sector_id)
|
|
{
|
|
case 14: //alpha-c
|
|
return_sector = 10601;
|
|
break;
|
|
case 15: //antares
|
|
return_sector = 10521;
|
|
break;
|
|
case 17: //aragoth
|
|
return_sector = 10201;
|
|
break;
|
|
case 19: //capella
|
|
return_sector = 10521;
|
|
break;
|
|
case 22: //
|
|
return_sector = 10651;
|
|
break;
|
|
case 35: //
|
|
return_sector = 10301;
|
|
break;
|
|
case 40: //Tau ceti
|
|
return_sector = 10601;
|
|
break;
|
|
case 41: //sirius
|
|
return_sector = 10551;
|
|
break;
|
|
default:
|
|
return_sector = 10601;
|
|
break;
|
|
}
|
|
LogMessage("Used lounge NPC of %d\n", return_sector);
|
|
}
|
|
|
|
SetCurrentDirectory(old_path);
|
|
return return_sector;
|
|
}
|
|
|
|
void Connection::SendDataFileToClient(char *filename, long avatar_id)
|
|
{
|
|
char old_path[MAX_PATH];
|
|
GetCurrentDirectory(sizeof(old_path), old_path);
|
|
SetCurrentDirectory(SERVER_DATABASE_PATH);
|
|
FILE *f = fopen(filename, "rb");
|
|
if (f)
|
|
{
|
|
fseek(f,0,SEEK_END);
|
|
long length = ftell(f);
|
|
if ((length > 0) && (length < TCP_BUFFER_SIZE))
|
|
{
|
|
LogMessage("Sending data file '%s'\n", filename);
|
|
fseek(f,0,SEEK_SET);
|
|
unsigned char * buffer = new unsigned char[length];
|
|
fread(buffer, 1, length, f);
|
|
if (avatar_id)
|
|
{
|
|
*((long *) &buffer[4]) = avatar_id;
|
|
}
|
|
m_CryptOut.RC4(buffer, length);
|
|
Send(buffer, length);
|
|
delete [] buffer;
|
|
}
|
|
else
|
|
{
|
|
LogMessage("SendDataFileToClient: Invalid file length %d : '%s'\n", length, filename);
|
|
}
|
|
fclose(f);
|
|
}
|
|
else
|
|
{
|
|
LogMessage("SendDataFileToClient: Unable to open %s\n", filename);
|
|
}
|
|
|
|
SetCurrentDirectory(old_path);
|
|
}
|
|
|
|
void Connection::SendConfirmedActionOffer()
|
|
{
|
|
unsigned char action_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x65,
|
|
0x07, 0x00, 0x4d, 0x65,
|
|
0x73, 0x73, 0x61, 0x67, 0x65
|
|
};
|
|
|
|
SendResponse(ENB_OPCODE_00BE_CONFIRMED_ACTION_OFFER, action_data, sizeof(action_data));
|
|
SendClientSound("push_mission_alert_sound", 2, 0);
|
|
}
|
|
|
|
void Connection::HandleActionResponse()
|
|
{
|
|
long player_id = ntohl(*((long *) &m_RecvBuffer[0]));
|
|
if (player_id == m_AvatarID)
|
|
{
|
|
m_ActionResponseReceived = true;
|
|
ProcessConfirmedActionOffer();
|
|
}
|
|
}
|
|
|
|
void Connection::ProcessConfirmedActionOffer()
|
|
{
|
|
int length;
|
|
char buffer[256];
|
|
memset(&buffer, 0, 256);
|
|
|
|
if (m_ActionResponseReceived == false)
|
|
{
|
|
SendConfirmedActionOffer();
|
|
//m_SectorMgr->AddTimedCall(m_Player, B_FORCE_LOGOUT, 20000,0);
|
|
}
|
|
else
|
|
{
|
|
//send the message
|
|
length = sprintf(buffer,"Hi %s, there is a new version of sockettest out now (v0.95), You need to download and use it to get correct movement.\
|
|
you will be logged out in 20 seconds from receipt of this message.\nCheers, TB.", m_Player->Name());
|
|
SendResponse(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) buffer, length+3);
|
|
|
|
{
|
|
AvatarDescription avatar;
|
|
memset(&avatar, 0, sizeof(avatar));
|
|
memcpy(&avatar.avatar_data, &m_Player->Database()->avatar, sizeof(avatar.avatar_data));
|
|
avatar.AvatarID = m_Player->GameID();
|
|
avatar.unknown3 = 1.0;
|
|
avatar.unknown4 = 1.0;
|
|
SendResponse(ENB_OPCODE_0061_AVATAR_DESCRIPTION, (unsigned char *) &avatar, sizeof(avatar));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::SendClientSetTime(long TimeSent)
|
|
{
|
|
ClientSetTime data;
|
|
data.ClientSent = TimeSent;
|
|
data.ServerReceived = GetNet7TickCount();
|
|
data.ServerSent = data.ServerReceived;
|
|
|
|
SendResponse(ENB_OPCODE_0034_CLIENT_SET_TIME, (unsigned char *) &data, sizeof(data));
|
|
|
|
//LogMessage("Sending SetClientTime packet 0x%08x\n",TimeSent);
|
|
}
|
|
|
|
void Connection::SendObjectToObjectLinkedEffect(Object *target, Object *source, short effect1, short effect2, float speedup)
|
|
{
|
|
unsigned char link_data[128];
|
|
memset(link_data,0,128);
|
|
int index = 0;
|
|
|
|
long effect_id = m_SectorMgr->GetSectorNextObjID();
|
|
|
|
AddData(link_data, effect_id, index);
|
|
AddData(link_data, GetNet7TickCount(), index);
|
|
AddData(link_data, source->GameID(), index);
|
|
AddData(link_data, (char)(0), index); //Unknown spacer
|
|
AddData(link_data, target->GameID(), index);
|
|
AddData(link_data, effect1, index); //DurationLinkedEffectDescID
|
|
AddData(link_data, effect2, index); //EffectDescID
|
|
AddData(link_data, 0.0f, index); //x offset from default target hit zone
|
|
AddData(link_data, 0.0f, index); //y offset //NB - we leave these at zero
|
|
AddData(link_data, 0.0f, index); //z offset // because the client seems to do a good job
|
|
AddData(link_data, (long)(0), index); //unknown (doesn't appear to be used)
|
|
AddData(link_data, (char)(1), index); //outside target radius
|
|
AddData(link_data, (float)(1.0f), index); //scale
|
|
AddData(link_data, (float)(0.0f), index); //HSV[0]
|
|
AddData(link_data, (float)(0.0f), index); //HSV[1]
|
|
AddData(link_data, (float)(0.0f), index); //HSV[2]
|
|
AddData(link_data, speedup, index); //speedup
|
|
|
|
SendResponse(ENB_OPCODE_000E_OBJECT_TO_OBJECT_LINKED_EFFECT, link_data, index);
|
|
}
|
|
|
|
void Connection::SendObjectEffect(ObjectEffect *obj_effect)
|
|
{
|
|
unsigned char effect[128];
|
|
memset(effect,0,128);
|
|
int index = 0;
|
|
|
|
AddData(effect, obj_effect->Bitmask, index);
|
|
AddData(effect, obj_effect->GameID, index);
|
|
AddData(effect, obj_effect->EffectDescID, index);
|
|
|
|
if (obj_effect->Bitmask & 0x01)
|
|
{
|
|
AddData(effect, obj_effect->EffectID, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x02)
|
|
{
|
|
if (obj_effect->TimeStamp == 0)
|
|
{
|
|
obj_effect->TimeStamp = GetNet7TickCount();
|
|
}
|
|
|
|
AddData(effect, obj_effect->TimeStamp, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x04)
|
|
{
|
|
AddData(effect, obj_effect->Duration, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x08)
|
|
{
|
|
AddData(effect, obj_effect->Scale, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x10)
|
|
{
|
|
AddData(effect, obj_effect->HSVShift[0], index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x20)
|
|
{
|
|
AddData(effect, obj_effect->HSVShift[1], index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x40)
|
|
{
|
|
AddData(effect, obj_effect->HSVShift[2], index);
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_0009_OBJECT_EFFECT, effect, index);
|
|
}
|
|
|
|
void Connection::SendClientType(long client_type)
|
|
{
|
|
//LogMessage("Sending ClientType packet\n");
|
|
SendResponse(ENB_OPCODE_003C_CLIENT_TYPE, (unsigned char *) &client_type, sizeof(client_type));
|
|
}
|
|
|
|
void Connection::SendStart(long start_id)
|
|
{
|
|
//LogMessage("Sending Start packet\n");
|
|
SendResponse(ENB_OPCODE_0005_START, (unsigned char *) &start_id, sizeof(start_id));
|
|
}
|
|
|
|
void Connection::SendSetBBox(float xmin, float ymin, float xmax, float ymax)
|
|
{
|
|
SetBBox bbox;
|
|
bbox.XMin = xmin;
|
|
bbox.YMin = ymin;
|
|
bbox.XMax = xmax;
|
|
bbox.YMax = ymax;
|
|
|
|
//LogMessage("Sending SetBBox packet\n");
|
|
SendResponse(ENB_OPCODE_002B_SET_BBOX, (unsigned char *) &bbox, sizeof(bbox));
|
|
}
|
|
|
|
void Connection::SendSetZBand(float min, float max)
|
|
{
|
|
SetZBand zband;
|
|
zband.Min = min;
|
|
zband.Max = min;
|
|
|
|
//LogMessage("Sending SetZBand packet\n");
|
|
SendResponse(ENB_OPCODE_002A_SET_ZBAND, (unsigned char *) &zband, sizeof(zband));
|
|
}
|
|
|
|
/*
|
|
--------------------
|
|
|
|
12 00 Length = 18 bytes
|
|
99 00 Opcode 0x99 = Navigation
|
|
6E 01 00 00 GameID
|
|
00 C8 2F 47 Sig
|
|
00 visited
|
|
02 00 00 00 Type
|
|
00 Ishuge*/
|
|
|
|
void Connection::SendNavigation(int game_id, float signature, char visited, int nav_type, char is_huge)
|
|
{
|
|
Navigation navigation;
|
|
navigation.GameID = game_id;
|
|
navigation.Signature = signature;
|
|
navigation.PlayerHasVisited = visited;
|
|
navigation.NavType = nav_type;
|
|
navigation.IsHuge = is_huge;
|
|
|
|
//LogMessage("Sending Navigation packet\n");
|
|
SendResponse(ENB_OPCODE_0099_NAVIGATION, (unsigned char *) &navigation, sizeof(navigation));
|
|
}
|
|
|
|
void Connection::SendCreateAttachment(int parent, int child, int slot)
|
|
{
|
|
CreateAttachment attachment;
|
|
attachment.Parent_ID = ntohl(parent);
|
|
attachment.Child_ID = ntohl(child);
|
|
attachment.Slot = ntohl(slot);
|
|
|
|
//LogMessage("Sending CreateAttachment packet\n");
|
|
SendResponse(ENB_OPCODE_004A_CREATE_ATTACHMENT, (unsigned char *) &attachment, sizeof(attachment));
|
|
}
|
|
|
|
void Connection::SendDecal(int game_id, int decal_id, int decal_count)
|
|
{
|
|
if (decal_count > MAX_DECALS)
|
|
{
|
|
decal_count = MAX_DECALS;
|
|
}
|
|
|
|
Decal decal;
|
|
decal.GameID = game_id;
|
|
decal.DecalCount = decal_count;
|
|
for (int i = 0; i < decal_count; i++)
|
|
{
|
|
decal.Item[i].Index = i + 1;
|
|
decal.Item[i].HSV[0] = 1.0;
|
|
decal.Item[i].HSV[1] = 1.0;
|
|
decal.Item[i].HSV[2] = 1.0;
|
|
decal.Item[i].opacity = 1.0;
|
|
}
|
|
|
|
size_t size = ((char *) &decal.Item[decal_count]) - ((char *) &decal);
|
|
|
|
//LogMessage("Sending Decal packet\n");
|
|
SendResponse(ENB_OPCODE_0010_DECAL, (unsigned char *) &decal, size);
|
|
}
|
|
|
|
void Connection::SendNameDecal(int game_id, char *shipname, float h, float s, float v)
|
|
{
|
|
NameDecal name_decal;
|
|
|
|
memset(&name_decal, 0, sizeof(name_decal));
|
|
name_decal.GameID = game_id;
|
|
name_decal.RGB[0] = h;
|
|
name_decal.RGB[1] = s;
|
|
name_decal.RGB[2] = v;
|
|
strncpy(name_decal.Name, shipname, sizeof(name_decal.Name) - 1);
|
|
|
|
//LogMessage("Sending NameDecal packet\n");
|
|
SendResponse(ENB_OPCODE_00B2_NAME_DECAL, (unsigned char *) &name_decal, sizeof(name_decal));
|
|
}
|
|
|
|
void Connection::SendConstantPositionalUpdate(long game_id, float x, float y, float z, float *orientation)
|
|
{
|
|
ConstantPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = game_id;
|
|
update.Position[0] = x;
|
|
update.Position[1] = y;
|
|
update.Position[2] = z;
|
|
if (orientation)
|
|
{
|
|
update.Orientation[0] = orientation[0];
|
|
update.Orientation[1] = orientation[1];
|
|
update.Orientation[2] = orientation[2];
|
|
update.Orientation[3] = orientation[3];
|
|
}
|
|
|
|
//LogMessage("Sending ConstantPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_0040_CONSTANT_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendFormationPositionalUpdate(long leader_id, long target_id, float x, float y, float z)
|
|
{
|
|
FormationPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.LeaderID = leader_id;
|
|
update.TargetID = target_id;
|
|
update.Position[0] = x;
|
|
update.Position[1] = y;
|
|
update.Position[2] = z;
|
|
|
|
//LogMessage("Sending FormationPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_0041_FORMATION_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendSimplePositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
SimplePositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = object_id;
|
|
update.TimeStamp = GetNet7TickCount();
|
|
update.Position[0] = position_info->Position[0];
|
|
update.Position[1] = position_info->Position[1];
|
|
update.Position[2] = position_info->Position[2];
|
|
update.Orientation[0] = position_info->Orientation[0];
|
|
update.Orientation[1] = position_info->Orientation[1];
|
|
update.Orientation[2] = position_info->Orientation[2];
|
|
update.Orientation[3] = position_info->Orientation[3];
|
|
update.Velocity[0] = position_info->Velocity[0];
|
|
update.Velocity[1] = position_info->Velocity[1];
|
|
update.Velocity[2] = position_info->Velocity[2];
|
|
|
|
//LogMessage("Sending SimplePositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_0008_SIMPLE_POSITIONAL_UDPATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendPlanetPositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
PlanetPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.GameID = object_id;
|
|
update.TimeStamp = GetNet7TickCount();
|
|
update.Position[0] = position_info->Position[0];
|
|
update.Position[1] = position_info->Position[1];
|
|
update.Position[2] = position_info->Position[2];
|
|
update.OrbitID = position_info->OrbitID;
|
|
update.OrbitDist = position_info->OrbitDist;
|
|
update.OrbitAngle = position_info->OrbitAngle;
|
|
update.OrbitRate = position_info->OrbitRate;
|
|
update.RotateAngle = position_info->RotateAngle;
|
|
update.RotateRate = position_info->RotateRate;
|
|
update.TiltAngle = position_info->TiltAngle;
|
|
|
|
//LogMessage("Sending PlanetPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_003F_PLANET_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendComponentPositionalUpdate(long object_id, PositionInformation * position_info, long timestamp)
|
|
{
|
|
ComponentPositionalUpdate update;
|
|
memset(&update, 0, sizeof(update));
|
|
|
|
update.simple.GameID = object_id;
|
|
if (timestamp)
|
|
{
|
|
update.simple.TimeStamp = timestamp;
|
|
}
|
|
else
|
|
{
|
|
update.simple.TimeStamp = GetNet7TickCount();
|
|
}
|
|
update.simple.Position[0] = position_info->Position[0];
|
|
update.simple.Position[1] = position_info->Position[1];
|
|
update.simple.Position[2] = position_info->Position[2];
|
|
update.simple.Orientation[0] = position_info->Orientation[0];
|
|
update.simple.Orientation[1] = position_info->Orientation[1];
|
|
update.simple.Orientation[2] = position_info->Orientation[2];
|
|
update.simple.Orientation[3] = position_info->Orientation[3];
|
|
update.simple.Velocity[0] = position_info->Velocity[0];
|
|
update.simple.Velocity[1] = position_info->Velocity[1];
|
|
update.simple.Velocity[2] = position_info->Velocity[2];
|
|
update.ImpartedDecay = position_info->ImpartedDecay;
|
|
update.TractorSpeed = position_info->TractorSpeed;
|
|
update.TractorID = position_info->TractorID;
|
|
update.TractorEffectID = position_info->TractorEffectID;
|
|
|
|
//LogMessage("Sending ComponentPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_0046_COMPONENT_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Connection::SendAdvancedPositionalUpdate(long object_id, PositionInformation * position_info)
|
|
{
|
|
char packet[sizeof(AdvancedPositionalUpdate)];
|
|
memset(packet, 0, sizeof(packet));
|
|
short *pBitmask = (short *) &packet[0];
|
|
long *pLong = (long *) &packet[2];
|
|
float *pFloat = (float *) &packet[2];
|
|
short bitmask = position_info->Bitmask;
|
|
int index = 0;
|
|
|
|
// Package the data into the packet
|
|
*pBitmask = bitmask;
|
|
pLong[index++] = object_id; // GameID
|
|
pLong[index++] = GetNet7TickCount(); // TimeStamp
|
|
pFloat[index++] = position_info->Position[0];
|
|
pFloat[index++] = position_info->Position[1];
|
|
pFloat[index++] = position_info->Position[2];
|
|
pFloat[index++] = position_info->Orientation[0];
|
|
pFloat[index++] = position_info->Orientation[1];
|
|
pFloat[index++] = position_info->Orientation[2];
|
|
pFloat[index++] = position_info->Orientation[3];
|
|
pLong[index++] = position_info->MovementID;
|
|
if (bitmask & 0x0001)
|
|
{
|
|
pFloat[index++] = position_info->CurrentSpeed;
|
|
}
|
|
if (bitmask & 0x0002)
|
|
{
|
|
pFloat[index++] = position_info->SetSpeed;
|
|
}
|
|
if (bitmask & 0x0004)
|
|
{
|
|
pFloat[index++] = position_info->Acceleration;
|
|
}
|
|
if (bitmask & 0x0008)
|
|
{
|
|
pFloat[index++] = position_info->RotY;
|
|
}
|
|
if (bitmask & 0x0010)
|
|
{
|
|
pFloat[index++] = position_info->DesiredY;
|
|
}
|
|
if (bitmask & 0x0020)
|
|
{
|
|
pFloat[index++] = position_info->RotZ;
|
|
}
|
|
if (bitmask & 0x0040)
|
|
{
|
|
pFloat[index++] = position_info->DesiredZ;
|
|
}
|
|
if (bitmask & 0x0080)
|
|
{
|
|
pFloat[index++] = position_info->ImpartedVelocity[0];
|
|
pFloat[index++] = position_info->ImpartedVelocity[1];
|
|
pFloat[index++] = position_info->ImpartedVelocity[2];
|
|
pFloat[index++] = position_info->ImpartedSpin;
|
|
pFloat[index++] = position_info->ImpartedRoll;
|
|
pFloat[index++] = position_info->ImpartedPitch;
|
|
}
|
|
if (bitmask & 0x0100)
|
|
{
|
|
pLong[index++] = position_info->UpdatePeriod;
|
|
}
|
|
|
|
//LogMessage("Sending AdvancedPositionalUpdate packet\n");
|
|
int length = 2 + 4 * index;
|
|
SendResponse(ENB_OPCODE_003E_ADVANCED_POSITIONAL_UPDATE, (unsigned char *) &packet, length);
|
|
}
|
|
|
|
void Connection::SendObjectToObjectEffect(ObjectToObjectEffect *obj_effect)
|
|
{
|
|
unsigned char effect[128];
|
|
memset(effect,0,128);
|
|
int index = 0;
|
|
|
|
AddData(effect, obj_effect->Bitmask, index);
|
|
AddData(effect, obj_effect->GameID, index);
|
|
AddData(effect, obj_effect->TargetID, index);
|
|
AddData(effect, obj_effect->EffectDescID, index);
|
|
|
|
if (obj_effect->Message)
|
|
{
|
|
AddDataS(effect, obj_effect->Message, index);
|
|
}
|
|
else
|
|
{
|
|
AddData(effect, (char)0, index);
|
|
}
|
|
|
|
if (obj_effect->Bitmask & 0x01)
|
|
{
|
|
AddData(effect, obj_effect->EffectID, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x02)
|
|
{
|
|
if (obj_effect->TimeStamp == 0)
|
|
{
|
|
obj_effect->TimeStamp = GetNet7TickCount();
|
|
}
|
|
|
|
AddData(effect, obj_effect->TimeStamp, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x04)
|
|
{
|
|
AddData(effect, obj_effect->Duration, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x08)
|
|
{
|
|
AddData(effect, obj_effect->TargetOffset[0], index);
|
|
AddData(effect, obj_effect->TargetOffset[1], index);
|
|
AddData(effect, obj_effect->TargetOffset[2], index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x10)
|
|
{
|
|
AddData(effect, obj_effect->OutsideTargetRadius, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x20) //from here on isn't correct - packet struct in packetstructures.h is wrong... TODO: work out correct packet structure.
|
|
{
|
|
AddData(effect, obj_effect->unused, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x40)
|
|
{
|
|
AddData(effect, obj_effect->Scale, index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x80)
|
|
{
|
|
AddData(effect, obj_effect->HSVShift[0], index);
|
|
AddData(effect, obj_effect->HSVShift[1], index);
|
|
AddData(effect, obj_effect->HSVShift[2], index);
|
|
}
|
|
if (obj_effect->Bitmask & 0x100)
|
|
{
|
|
AddData(effect, obj_effect->Speedup, index);
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_000B_OBJECT_TO_OBJECT_EFFECT, effect, index);
|
|
}
|
|
|
|
void Connection::SendPointEffect(int effect_id, float x, float y, float z, short duration,
|
|
short effect_desc_id, float scale, float h, float s, float v )
|
|
{
|
|
}
|
|
|
|
void Connection::SendActivateRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
//LogMessage("Sending ActivateRenderState packet\n");
|
|
SendResponse(ENB_OPCODE_0030_ACTIVATE_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
|
|
//TODO: Find out more about packet data structure - this is just a guess.
|
|
void Connection::SendInitRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
InitRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
SendResponse(ENB_OPCODE_002F_INIT_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Connection::SendActivateNextRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
//LogMessage("Sending ActivateRenderState packet\n");
|
|
SendResponse(ENB_OPCODE_0031_ACTIVATE_NEXT_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Connection::SendDeactivateRenderState(long game_id)
|
|
{
|
|
/*ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;*/
|
|
|
|
//LogMessage("Sending ActivateRenderState packet\n");
|
|
SendResponse(ENB_OPCODE_0032_DEACTIVATE_RENDER_STATE, (unsigned char *) &game_id, sizeof(game_id));
|
|
}
|
|
|
|
void Connection::SendCreate(int game_id, float scale, short asset, int type, float h, float s, float v)
|
|
{
|
|
Create create;
|
|
create.GameID = game_id;
|
|
create.Scale = scale;
|
|
create.BaseAsset = asset;
|
|
create.Type = (char) type;
|
|
create.HSV[0] = h;
|
|
create.HSV[1] = s;
|
|
create.HSV[2] = v;
|
|
|
|
//LogMessage("Sending Create packet\n");
|
|
SendResponse(ENB_OPCODE_0004_CREATE, (unsigned char *) &create, sizeof(create));
|
|
}
|
|
|
|
void Connection::HandleSkillStringRequest()
|
|
{
|
|
ClientSkillsRequest * request = (ClientSkillsRequest *) m_RecvBuffer;
|
|
|
|
//Loot item
|
|
//not sure if this packet is used for anything other than looting
|
|
|
|
//check we're targetting a HUSK
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
//TODO: set and check loot timer.
|
|
if (obj && obj->ObjectType() == OT_HUSK)
|
|
{
|
|
//Now check no-one else is looting this object
|
|
char *player = obj->CheckResourceLock();
|
|
if (player)
|
|
{
|
|
m_Player->SendVaMessage("%s currently being looted by %s", obj->Name(), player);
|
|
}
|
|
else
|
|
{
|
|
SendClientSound("coin.wav",0, 0);
|
|
long id = ntohl(obj->GameID());
|
|
SendResponse(ENB_OPCODE_008C_LOOT_HULK_PERMISSION, (unsigned char *)&id, sizeof(long));
|
|
m_ProspectWindow = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::HandleStartAck()
|
|
{
|
|
LogDebug("Received StartAck packet\n");
|
|
|
|
// Added to do things on sector change at top of 'Player' class
|
|
// don't put them here!!
|
|
|
|
//send the login camera just after we finally log in
|
|
m_Player->SendLoginCamera();
|
|
}
|
|
|
|
void Connection::HandleRequestTime()
|
|
{
|
|
LogDebug("Received RequestTime packet\n");
|
|
|
|
// Set the client time
|
|
// This is extremely high priority
|
|
SendClientSetTime(*((long *) m_RecvBuffer));
|
|
//don't set the connection as active until we get the time RQ
|
|
SetActive(true);
|
|
}
|
|
|
|
void Connection::HandleClientChatRequest()
|
|
{
|
|
ClientChatRequest * request = (ClientChatRequest *) m_RecvBuffer;
|
|
|
|
//LogMessage("Received ClientChatRequest packet\n");
|
|
//char Nick[30], Message[200];
|
|
char * string1 = "";
|
|
char * string2 = "";
|
|
char * string3 = "";
|
|
|
|
short length1 = request->string_length;
|
|
char *p = ((char *) &request->string_length);
|
|
p += sizeof(short);
|
|
if (length1)
|
|
{
|
|
string1 = new char[length1 + 1];
|
|
if (string1)
|
|
{
|
|
memcpy(string1, p, length1);
|
|
string1[length1] = 0;
|
|
p += length1;
|
|
}
|
|
}
|
|
short length2 = *((short *) p);
|
|
p += sizeof(short);
|
|
if (length2)
|
|
{
|
|
string2 = new char[length2 + 1];
|
|
if (string2)
|
|
{
|
|
memcpy(string2, p, length2);
|
|
string2[length2] = 0;
|
|
p += length2;
|
|
}
|
|
}
|
|
short length3 = *((short *) p);
|
|
p += sizeof(short);
|
|
if (length3)
|
|
{
|
|
string3 = new char[length3 + 1];
|
|
if (string3)
|
|
{
|
|
memcpy(string3, p, length3);
|
|
string3[length3] = 0;
|
|
p += length3;
|
|
}
|
|
}
|
|
long unknown2 = *((long *) p);
|
|
//LogMessage("PlayerID=%d arg1=%d arg2=%d\n",
|
|
// request->PlayerID, request->unknown1, unknown2);
|
|
//LogMessage("String1=\"%s\"\n", string1);
|
|
//LogMessage("String2=\"%s\"\n", string2);
|
|
//LogMessage("String3=\"%s\"\n", string3);
|
|
|
|
// sprintf(Nick, "%s", string1);
|
|
//sprintf(Message, "%s", string3);
|
|
if (request->unknown1 == 1)
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.ChatSendPrivate(m_AvatarID, string1, string3);
|
|
}
|
|
|
|
if (request->unknown1 == 0) // Channel Message
|
|
{
|
|
//LogMessage("ClientChatRequest: SendToChannel: %s Message: %s\n", string2, string3);
|
|
m_ServerMgr.m_PlayerMgr.ChatSendChannel(m_AvatarID, string2, string3);
|
|
}
|
|
|
|
if (length1)
|
|
{
|
|
delete [] string1;
|
|
}
|
|
if (length2)
|
|
{
|
|
delete [] string2;
|
|
}
|
|
if (length3)
|
|
{
|
|
delete [] string3;
|
|
}
|
|
}
|
|
|
|
void Connection::HandleTurn()
|
|
{
|
|
struct PacketTurn {
|
|
long GameID;
|
|
float Intensity;
|
|
} ATTRIB_PACKED;
|
|
|
|
PacketTurn * Turning = (PacketTurn *) m_RecvBuffer;
|
|
|
|
if (!m_Player->WarpDrive())
|
|
{
|
|
m_Player->AbortProspecting(true,false);
|
|
m_Player->Turn(Turning->Intensity);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleTilt()
|
|
{
|
|
struct PacketTurn {
|
|
long GameID;
|
|
float Intensity;
|
|
} ATTRIB_PACKED;
|
|
|
|
PacketTurn * Turning = (PacketTurn *) m_RecvBuffer;
|
|
|
|
if (!m_Player->WarpDrive())
|
|
{
|
|
m_Player->AbortProspecting(true,false);
|
|
m_Player->Tilt(Turning->Intensity);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleMove()
|
|
{
|
|
MovePacket * Movement = (MovePacket *) m_RecvBuffer;
|
|
|
|
if (!m_Player->WarpDrive())
|
|
{
|
|
m_Player->AbortProspecting(true,false);
|
|
|
|
//LogMessage("Received Move packet Type: %d\n", Movement->type);
|
|
if (Movement->type == 4)
|
|
{
|
|
m_Player->SendContrails(false);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendContrails(true);
|
|
}
|
|
|
|
m_Player->Move(Movement->type);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleWarp()
|
|
{
|
|
WarpPacket * warp = (WarpPacket *) m_RecvBuffer;
|
|
|
|
if (m_Player->WarpDrive())
|
|
{
|
|
m_Player->TerminateWarp(true);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendContrails(false);
|
|
LogDebug("Warp Navs: %ld, GameID=%d (%s)\n", warp->Navs, (warp->GameID & 0x00FFFFFF), m_Player->Name());
|
|
m_Player->SetupWarpNavs(warp->Navs, warp->TargetID);
|
|
m_Player->PrepareForWarp();
|
|
}
|
|
}
|
|
|
|
void Connection::Contrails(long player_id, bool contrails)
|
|
{
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x13, 0x00,
|
|
0x01,
|
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
if (contrails == true)
|
|
{
|
|
*((long*) &aux_data[15]) = 1;
|
|
}
|
|
|
|
*((long *) aux_data) = player_id;
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
|
|
void Connection::SendResourceName(long resourceID, char *resource_name)
|
|
{
|
|
unsigned char aux_data[64];
|
|
memset(aux_data, 0, 64);
|
|
short length = strlen(resource_name);
|
|
*((long *) aux_data) = resourceID;
|
|
*((short *) &aux_data[4]) = length + 4;
|
|
*((short *) &aux_data[6]) = 0x1201;
|
|
*((short *) &aux_data[8]) = length;
|
|
|
|
strncpy((char*)&aux_data[10], resource_name, length);
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, length+10);
|
|
}
|
|
|
|
//this is the same way that the live server sent husk content, but it is horrendously inefficient
|
|
//I wonder if there's a better way we can send Husk content
|
|
//We can re-do this now with Net7Proxy
|
|
void Connection::SendHuskContent(Object *husk)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (husk)
|
|
{
|
|
contents_already_sent = husk->GetIndex(m_Player->ResourceSendList());
|
|
|
|
if (!contents_already_sent)
|
|
{
|
|
unsigned char spacer[4] =
|
|
{
|
|
0x36, 0x00, 0xFF
|
|
};
|
|
unsigned char filler[8] =
|
|
{
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF
|
|
};
|
|
unsigned char prologue1[] =
|
|
{
|
|
0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F
|
|
};
|
|
unsigned char prologue2[] =
|
|
{
|
|
0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F
|
|
};
|
|
|
|
unsigned char aux_data[512];
|
|
int index = 0;
|
|
int x;
|
|
|
|
short length = strlen(husk->Name());
|
|
AddData(aux_data, husk->GameID(), index);
|
|
AddData(aux_data, (short)0x0000, index);
|
|
AddData(aux_data, (long) (0x0FEC1601), index);
|
|
AddData(aux_data, (short)(length), index);
|
|
AddDataS(aux_data, husk->Name(), index);
|
|
AddData(aux_data, (long)0x05050505, index);
|
|
|
|
ContentSlot *slot;
|
|
|
|
AddBuffer(aux_data, prologue1, 6, index);
|
|
|
|
for (x = 0; x < 20; x++)
|
|
{
|
|
AddBuffer(aux_data, filler, 7, index);
|
|
}
|
|
|
|
AddBuffer(aux_data, prologue2, 11, index);
|
|
|
|
for (x = 0; x < MAX_ITEMS_PER_RESOURCE; x++)
|
|
{
|
|
slot = husk->GetContents(x);
|
|
if (slot->stack > 0 && slot->item)
|
|
{
|
|
AddBuffer(aux_data, spacer, 3, index);
|
|
AddData(aux_data, slot->item->ItemTemplateID(), index);
|
|
AddData(aux_data, long(slot->stack), index);
|
|
m_Player->SendItemBase(slot->item->ItemTemplateID());
|
|
}
|
|
else
|
|
{
|
|
AddBuffer(aux_data, filler, 7, index);
|
|
}
|
|
}
|
|
|
|
for (x = 0; x < 32; x++)
|
|
{
|
|
AddBuffer(aux_data, filler, 7, index);
|
|
}
|
|
|
|
//set length
|
|
*((short *) &aux_data[4]) = index-8;
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, index);
|
|
husk->SetIndex(m_Player->ResourceSendList());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Connection::SendHuskName(Object *husk)
|
|
{
|
|
unsigned char aux_data[64];
|
|
memset(aux_data, 0, 64);
|
|
int index = 0;
|
|
|
|
short length = strlen(husk->Name());
|
|
AddData(aux_data, husk->GameID(), index);
|
|
AddData(aux_data, (short)(length+10), index);
|
|
AddData(aux_data, (long) (0x03E01601), index);
|
|
AddData(aux_data, (short)(length), index);
|
|
AddDataS(aux_data, husk->Name(), index);
|
|
AddData(aux_data, (long)0x05050505, index);
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, index);
|
|
}
|
|
|
|
void Connection::SendMobName(Object *mob)
|
|
{
|
|
int length = strlen(mob->Name());
|
|
if (length > 24) length = 24;
|
|
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00, //game id
|
|
0x3B, 0x00, //AUX length
|
|
0x01,
|
|
0x16, 0x30, 0x00, 0x40, 0x00, 0x00, 0x0C, 0x80, 0x03,
|
|
0x00, 0xBE, 0x40, 0xF8, 0xC0, 0x07, //always the same
|
|
|
|
0x18, 0x00, //[22]
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //[24]
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0xDA, 0x42, 0x00, 0x00, 0xDA, 0x42, //[48] (Hull strength)
|
|
0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, //[56] (MOB level)
|
|
0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
*((long *) aux_data) = mob->GameID();
|
|
*((short *) &aux_data[22]) = (short)length;
|
|
|
|
strncpy((char*)(&aux_data[24]), mob->Name(), length);
|
|
|
|
*((long *) &aux_data[56]) = mob->Level();
|
|
|
|
if (length < 24)
|
|
{
|
|
memcpy((&aux_data[24+length]), (&aux_data[48]), 25);
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
|
|
void Connection::SendSimpleAuxName(Object *obj)
|
|
{
|
|
int length = strlen(obj->Name()) + 10;
|
|
char *packet = (char*)_alloca(length);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = strlen(obj->Name()) + 4;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x12;
|
|
*((short *) &packet[8]) = strlen(obj->Name());
|
|
strncpy(&packet[10], obj->Name(), strlen(obj->Name()));
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length);
|
|
}
|
|
|
|
void Connection::SendAuxNameSignature(Object *obj)
|
|
{
|
|
char *name = "d";
|
|
if (obj->IsNav())
|
|
{
|
|
name = obj->Name();
|
|
}
|
|
|
|
int length = strlen(name) + 15;
|
|
char *packet = (char*)_alloca(length);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = strlen(name) + 9;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x72;
|
|
*((short *) &packet[8]) = strlen(name);
|
|
strncpy(&packet[10], name, strlen(name));
|
|
int i = 10 + strlen(name);
|
|
packet[i++] = obj->IsNav();
|
|
*((float *) &packet[i]) = obj->Signature();
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length);
|
|
}
|
|
|
|
void Connection::SendAuxNameResource(Object *obj)
|
|
{
|
|
int length = strlen(obj->Name()) + 11;
|
|
char *packet = (char*)_alloca(length);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = strlen(obj->Name()) + 5;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x16;
|
|
packet[8] = 0x04;
|
|
*((short *) &packet[9]) = strlen(obj->Name());
|
|
strncpy(&packet[11], obj->Name(), strlen(obj->Name()));
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length);
|
|
}
|
|
|
|
void Connection::UnSetTarget(long GameID)
|
|
{
|
|
if (m_Player->ShipIndex()->GetTargetGameID() == GameID)
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
//LogMessage("Sending SetTarget packet\n");
|
|
SendSetTarget(0, -1);
|
|
|
|
// Display nothing
|
|
m_Player->ShipIndex()->SetTargetThreatLevel(-1);
|
|
m_Player->ShipIndex()->SetTargetThreat("");
|
|
m_Player->ShipIndex()->SetTargetGameID(-1);
|
|
m_Player->SendAuxShip();
|
|
m_Player->BlankVerbs();
|
|
}
|
|
}
|
|
|
|
void Connection::ActivateProspectBeam(long player_id, long target_id, char *message, short effect_type, long effectUID, long timestamp, short effect_time)
|
|
{
|
|
ObjectToObjectEffect Prospect;
|
|
|
|
if (effect_time == 0)
|
|
{
|
|
Prospect.Bitmask = 0x03;
|
|
}
|
|
else
|
|
{
|
|
Prospect.Bitmask = 0x07;
|
|
}
|
|
Prospect.GameID = player_id;
|
|
Prospect.TargetID = target_id;
|
|
Prospect.EffectDescID = effect_type;// 0x00BF;
|
|
Prospect.Message = message;
|
|
Prospect.EffectID = effectUID;
|
|
Prospect.Duration = short(effect_time);
|
|
Prospect.TimeStamp = timestamp;
|
|
|
|
SendObjectToObjectEffect(&Prospect);
|
|
}
|
|
|
|
int LevelXP[] = { 500,1000,1500,2000,3000,4000,5000,7000,9000,11000,13000,15000,20000,25000,
|
|
30000,35000,40000,47500,55000,62500,70000,77500,87500,97500,107500,117500,127500,
|
|
140000,152500,165000,177500,190000,205000,220000,235000,250000,265000,285000,305000,
|
|
325000,345000,365000,390000,415000,440000,475000,510000,545000,595000,645000,
|
|
// Added XP for levels over 50
|
|
645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,
|
|
645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,
|
|
645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,
|
|
645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,
|
|
645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000,645000
|
|
};
|
|
|
|
|
|
//XP methods (the "xxx experience earned: xxx" message must be sent by parent method)
|
|
|
|
void Connection::AddCombatXP(char * mob_name, long XP_Gain, bool SkipGroup)
|
|
{
|
|
bool GroupXP = false;
|
|
char msg_buffer[128];
|
|
|
|
#ifdef BETA_TESTING
|
|
XP_Gain *= 2;
|
|
#endif
|
|
|
|
if (!SkipGroup)
|
|
{
|
|
GroupXP = m_ServerMgr.m_PlayerMgr.GroupXP(m_Player, mob_name, XP_Gain, m_Player->GroupID(), 0); // 0 = Combat 1 = Explore
|
|
}
|
|
|
|
if (!GroupXP)
|
|
{
|
|
u32 myCombatLevel = m_Player->PlayerIndex()->RPGInfo.GetCombatLevel();
|
|
u32 mySkillPointsEarned = 0;
|
|
|
|
if (myCombatLevel > 50)
|
|
{
|
|
myCombatLevel = 50;
|
|
}
|
|
|
|
long XP = (long)(m_Player->PlayerIndex()->RPGInfo.GetCombatXP() * LevelXP[myCombatLevel]) + XP_Gain;
|
|
|
|
while (XP >= LevelXP[myCombatLevel])
|
|
{
|
|
XP -= LevelXP[myCombatLevel];
|
|
if (myCombatLevel <= 19)
|
|
{
|
|
mySkillPointsEarned++;
|
|
myCombatLevel++;
|
|
}
|
|
else if (myCombatLevel <= 39)
|
|
{
|
|
mySkillPointsEarned += 2;
|
|
myCombatLevel++;
|
|
}
|
|
else if (myCombatLevel < 50)
|
|
{
|
|
mySkillPointsEarned += 3;
|
|
myCombatLevel++;
|
|
}
|
|
else
|
|
{
|
|
mySkillPointsEarned++;
|
|
//TODO: distribute XP to other bars
|
|
}
|
|
}
|
|
|
|
float myCombatXP = (float)(XP)/(float)(LevelXP[myCombatLevel]);
|
|
|
|
if (!SkipGroup)
|
|
{
|
|
sprintf(msg_buffer, "%s %d Combat experience earned", mob_name, XP_Gain);
|
|
SendPriorityMessageString(msg_buffer,"MessageLine",5000,4);
|
|
}
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetCombatXP(myCombatXP);
|
|
|
|
if (mySkillPointsEarned > 0)
|
|
{
|
|
SendClientSound("Player_Levels",0,1);
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetCombatLevel(myCombatLevel);
|
|
m_Player->PlayerIndex()->RPGInfo.SetSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetSkillPoints() + mySkillPointsEarned);
|
|
m_Player->PlayerIndex()->RPGInfo.SetTotalSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetTotalSkillPoints() + mySkillPointsEarned);
|
|
|
|
SendPushMessage("LEVEL UP!","QuickLine",0,3);
|
|
sprintf(msg_buffer, "Combat level is now %d!", myCombatLevel);
|
|
SendPushMessage(msg_buffer, "MessageLine", 3000, 3);
|
|
|
|
// Update the combat level display when targeting
|
|
m_Player->ShipIndex()->SetCombatLevel(myCombatLevel);
|
|
m_Player->ShipIndex()->SetRank(m_Player->GetRank());
|
|
m_Player->SendAuxShip();
|
|
|
|
m_Player->LevelUpForSkills();
|
|
m_Player->UpdateSkills();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::AddExploreXP(char * raw_name, long XP_Gain, bool SkipGroup)
|
|
{
|
|
bool GroupXP = false;
|
|
char msg_buffer[128];
|
|
|
|
#ifdef BETA_TESTING
|
|
XP_Gain *= 2;
|
|
#endif
|
|
|
|
if (!SkipGroup)
|
|
{
|
|
GroupXP = m_ServerMgr.m_PlayerMgr.GroupXP(m_Player, raw_name, XP_Gain, m_Player->GroupID(), 1); // 0 = Combat 1 = Explore
|
|
}
|
|
|
|
if (!GroupXP)
|
|
{
|
|
u32 myExploreLevel = m_Player->PlayerIndex()->RPGInfo.GetExploreLevel();
|
|
u32 mySkillPointsEarned = 0;
|
|
|
|
if (myExploreLevel > 50)
|
|
{
|
|
myExploreLevel = 50;
|
|
}
|
|
|
|
long XP = (long)(m_Player->PlayerIndex()->RPGInfo.GetExploreXP() * LevelXP[myExploreLevel]) + XP_Gain;
|
|
|
|
while (XP >= LevelXP[myExploreLevel])
|
|
{
|
|
XP -= LevelXP[myExploreLevel];
|
|
if (myExploreLevel <= 19)
|
|
{
|
|
mySkillPointsEarned++;
|
|
myExploreLevel++;
|
|
}
|
|
else if (myExploreLevel <= 39)
|
|
{
|
|
mySkillPointsEarned += 2;
|
|
myExploreLevel++;
|
|
}
|
|
else if (myExploreLevel < 50)
|
|
{
|
|
mySkillPointsEarned += 3;
|
|
myExploreLevel++;
|
|
}
|
|
else
|
|
{
|
|
mySkillPointsEarned++;
|
|
//TODO: distribute XP to other bars
|
|
}
|
|
}
|
|
|
|
float myExploreXP = (float)(XP)/(float)LevelXP[myExploreLevel];
|
|
|
|
if (!SkipGroup)
|
|
{
|
|
sprintf(msg_buffer, "%s %d Explore experience earned", raw_name, XP_Gain);
|
|
SendPriorityMessageString(msg_buffer,"MessageLine",5000,4);
|
|
}
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetExploreXP(myExploreXP);
|
|
|
|
if (mySkillPointsEarned > 0)
|
|
{
|
|
SendClientSound("Player_Levels",0,1);
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetExploreLevel(myExploreLevel);
|
|
m_Player->PlayerIndex()->RPGInfo.SetSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetSkillPoints() + mySkillPointsEarned);
|
|
m_Player->PlayerIndex()->RPGInfo.SetTotalSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetTotalSkillPoints() + mySkillPointsEarned);
|
|
|
|
SendPushMessage("LEVEL UP!","QuickLine",0,3);
|
|
sprintf(msg_buffer, "Explore level is now %d!", myExploreLevel);
|
|
SendPushMessage(msg_buffer, "MessageLine", 3000, 3);
|
|
|
|
m_Player->LevelUpForSkills();
|
|
m_Player->UpdateSkills();
|
|
m_Player->ShipIndex()->SetRank(m_Player->GetRank());
|
|
m_Player->SendAuxShip();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::AddTradeXP(char * name, long XP_Gain, bool SkipGroup)
|
|
{
|
|
char msg_buffer[128];
|
|
|
|
u32 myTradeLevel = m_Player->PlayerIndex()->RPGInfo.GetTradeLevel();
|
|
u32 mySkillPointsEarned = 0;
|
|
|
|
#ifdef BETA_TESTING
|
|
XP_Gain *= 2;
|
|
#endif
|
|
|
|
sprintf(msg_buffer, "%s %d Trade experience earned", name, XP_Gain);
|
|
SendPriorityMessageString(msg_buffer,"MessageLine",5000,4);
|
|
|
|
if (myTradeLevel > 50)
|
|
{
|
|
myTradeLevel = 50;
|
|
}
|
|
|
|
long XP = (long)(m_Player->PlayerIndex()->RPGInfo.GetTradeXP() * LevelXP[myTradeLevel]) + XP_Gain;
|
|
|
|
while (XP >= LevelXP[myTradeLevel])
|
|
{
|
|
XP -= LevelXP[myTradeLevel];
|
|
if (myTradeLevel <= 19)
|
|
{
|
|
mySkillPointsEarned++;
|
|
myTradeLevel++;
|
|
}
|
|
else if (myTradeLevel <= 39)
|
|
{
|
|
mySkillPointsEarned += 2;
|
|
myTradeLevel++;
|
|
}
|
|
else if (myTradeLevel < 50)
|
|
{
|
|
mySkillPointsEarned += 3;
|
|
myTradeLevel++;
|
|
}
|
|
else
|
|
{
|
|
mySkillPointsEarned++;
|
|
//TODO: distribute XP to other bars
|
|
}
|
|
}
|
|
|
|
float myTradeXP = (float)(XP)/(float)(LevelXP[myTradeLevel]);
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetTradeXP(myTradeXP);
|
|
|
|
if (mySkillPointsEarned > 0)
|
|
{
|
|
SendClientSound("Player_Levels",0,1);
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetTradeLevel(myTradeLevel);
|
|
m_Player->PlayerIndex()->RPGInfo.SetSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetSkillPoints() + mySkillPointsEarned);
|
|
m_Player->PlayerIndex()->RPGInfo.SetTotalSkillPoints(m_Player->PlayerIndex()->RPGInfo.GetTotalSkillPoints() + mySkillPointsEarned);
|
|
|
|
SendPushMessage("LEVEL UP!","QuickLine",0,3);
|
|
sprintf(msg_buffer, "Trade level is now %d!", myTradeLevel);
|
|
SendPushMessage(msg_buffer, "MessageLine", 3000, 3);
|
|
|
|
m_Player->LevelUpForSkills();
|
|
m_Player->UpdateSkills();
|
|
m_Player->ShipIndex()->SetRank(m_Player->GetRank());
|
|
m_Player->SendAuxShip();
|
|
}
|
|
}
|
|
|
|
void Connection::AddMOBDestroyExperience(short mob_level, char *mob_name)
|
|
{
|
|
char msg_buffer[128];
|
|
|
|
short myXPEarned = 250 + 100 * (mob_level / (m_Player->PlayerIndex()->RPGInfo.GetCombatLevel() + 1));
|
|
|
|
LogMessage("Mob XP: %d MobLevel: %d (%s)\n", myXPEarned, mob_level, m_Player->Name());
|
|
|
|
// Cap it at 1600
|
|
if (myXPEarned > 1600) myXPEarned = 1600;
|
|
if (myXPEarned <= 0) myXPEarned = 0;
|
|
|
|
sprintf(msg_buffer, "Defeated %s:", mob_name);
|
|
|
|
AddCombatXP(msg_buffer, myXPEarned);
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
|
|
void Connection::SendPushMessage(char *msg1, char *type, long time, long priority)
|
|
{
|
|
unsigned char packet[128];
|
|
memset(packet,0,128);
|
|
unsigned char *pptr = &packet[0];
|
|
int index = 0;
|
|
|
|
AddDataS(pptr, msg1, index);
|
|
AddData(pptr, char(0), index);
|
|
AddDataS(pptr, type, index);
|
|
AddData(pptr, char(0), index);
|
|
AddData(pptr, time, index);
|
|
AddData(pptr, priority, index);
|
|
|
|
SendResponse(ENB_OPCODE_0022_PUSH_MESSAGE, pptr, index);
|
|
}
|
|
|
|
void Connection::SetResourceDrainLevel(Object *obj, long slot)
|
|
{
|
|
unsigned long slot_index = ((0x10 << slot) | 0x02); //slot index calc
|
|
long length = 28;
|
|
//Control which resource gets removed and how much of the resource is left
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x16, 0x00,
|
|
0x01, // 6
|
|
0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, //the second byte value determines which resource to remove ((0x10 << slot) | 0x02)
|
|
0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00 // amount of colour left in resource - 0 is collapse
|
|
};
|
|
|
|
*((long *) aux_data) = obj->GameID();
|
|
*((long *) &aux_data[8]) = slot_index;
|
|
*((float *) &aux_data[24]) = obj->ResourceRemains();
|
|
|
|
if (obj->GetStack(slot) > 0)
|
|
{
|
|
length = 24;
|
|
*((char *) &aux_data[4]) = 0x12; //new size
|
|
*((char *) &aux_data[14]) = 0x22; //indicates partial removal
|
|
*((long *) &aux_data[16]) = obj->GetStack(slot) ; //resource remaining in this slot
|
|
*((float *) &aux_data[20]) = obj->ResourceRemains();
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, length); //this seems to initiate resource collapse or drains the resource according to last float val
|
|
}
|
|
|
|
void Connection::RemoveObject(long object_id)
|
|
{
|
|
UnSetTarget(object_id);
|
|
SendResponse(ENB_OPCODE_0007_REMOVE, (unsigned char *) &object_id, sizeof(object_id)); //remove the raw resource
|
|
}
|
|
|
|
//This is where I put all the AUX prospecting stuff I don't really understand
|
|
//any help decoding any of this appreciated!
|
|
|
|
//TODO: REMOVE THIS!!
|
|
void Connection::SendProspectAUX(long value, int type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
{
|
|
//non-parsemode AuxPlayer
|
|
//sets prospect skill last activation time
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x15, 0x00,
|
|
0x00,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
0x59, 0x0B, 0x00, 0x00, //always this for prospecting
|
|
0x64, 0x4C, 0x20, 0x25, //timestamp...
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
*((long *) &aux_data[15]) = value;
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
//second type of AUX prospecting requires to be sent
|
|
//diables the users cloak and advancd cloak abilities
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x1D, 0x00,
|
|
0x00,
|
|
0x02, 0x00, 0x00, 0x00,
|
|
0x15, 0x0C, 0x00, 0x00,
|
|
0x00, 0x01, 0x00, 0x00,
|
|
0xF5, 0x0C, 0x00, 0x00,
|
|
0x00, 0x01, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
}; //no idea what this does, but always the same for prospect. Maybe some effect?
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
m_Player->ShipIndex()->SetTargetGameID(0);
|
|
m_Player->SendAuxShip();
|
|
m_Player->BlankVerbs();
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
//AuxShip Packet (most likely "disables" weapons)
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x1C, 0x00,
|
|
0x01,
|
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, //inventory
|
|
0x02, 0x08, //equip inventory
|
|
0x22, 0x08, 0x00, //items 1 and 7
|
|
0x02, 0x00, 0x01, //equipitem flags
|
|
0x10, 0x20, 0x00, 0x00, //itemstats
|
|
0x02, 0x00, 0x01, //equipitem flags
|
|
0x10, 0x20, 0x00, 0x00 //itemstats
|
|
};
|
|
*((long *) aux_data) = value;
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
//re-enables the users cloak and advancd cloak abilities
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x1D, 0x00,
|
|
0x00,
|
|
0x02, 0x00, 0x00, 0x00,
|
|
0x15, 0x0C, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0xF5, 0x0C, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
}; //no idea what this does, but always the same for prospect. Maybe some effect?
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Connection::CreateTractorComponent(float *position, float decay, float tractor_speed, long player_id, long article_id, long effect_id, long timestamp)
|
|
{
|
|
PositionInformation pos_info;
|
|
|
|
memset(&pos_info, 0, sizeof(PositionInformation));
|
|
|
|
pos_info.Position[0] = position[0];
|
|
pos_info.Position[1] = position[1];
|
|
pos_info.Position[2] = position[2];
|
|
pos_info.Orientation[4] = 1.0f;
|
|
pos_info.ImpartedDecay = decay;
|
|
pos_info.TractorSpeed = tractor_speed;
|
|
pos_info.TractorID = player_id;//playerID
|
|
pos_info.TractorEffectID= effect_id;
|
|
|
|
SendComponentPositionalUpdate(
|
|
article_id,
|
|
&pos_info,
|
|
timestamp);
|
|
}
|
|
|
|
void Connection::HandleInventoryMove()
|
|
{
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
m_Player->SendVaMessageC(17, "Cannot manipulate inventory while incapacitated");
|
|
return;
|
|
}
|
|
|
|
InvMove * Inventory = (InvMove *) m_RecvBuffer;
|
|
InvMove InvMo;
|
|
|
|
_Item Source, Destination;
|
|
|
|
InvMo.FromInv = ntohl(Inventory->FromInv);
|
|
InvMo.FromSlot = ntohl(Inventory->FromSlot);
|
|
InvMo.ToSlot = ntohl(Inventory->ToSlot);
|
|
InvMo.ToInv = ntohl(Inventory->ToInv);
|
|
InvMo.GameID = ntohl(Inventory->GameID);
|
|
InvMo.Num = ntohl(Inventory->Num);
|
|
|
|
LogDebug("Inventory Move - GameID: %ld From %ld Slot: %ld To: %ld Slot %ld Number: %ld\n", InvMo.GameID,InvMo.FromInv,
|
|
InvMo.FromSlot, InvMo.ToInv, InvMo.ToSlot, InvMo.Num);
|
|
|
|
// if you are incapacited you cant equip items
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to move inventory while incapacitated.", 11);
|
|
return;
|
|
}
|
|
|
|
//you can only move certain items from certain places (cannot equip from vault, ect)
|
|
switch(InvMo.FromInv)
|
|
{
|
|
// From Cargo Inventory
|
|
case 1:
|
|
Source = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if (InvMo.ToInv == 1) //cargo to cargo
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else if(InvMo.ToInv == 2) //equip from cargo
|
|
{
|
|
if (!m_Player->m_Equip[InvMo.ToSlot].CanEquip(&Source))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//If we are moving ammo, they can stack if they are the same itemid
|
|
if (m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetItemTemplateID() == Source.ItemTemplateID)
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetData();
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
m_Player->m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
else
|
|
{
|
|
Destination = m_Player->m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else if(InvMo.ToInv == 3) //cargo to vault
|
|
{
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Destination = *m_Player->PlayerIndex()->SecureInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Player->PlayerIndex()->SecureInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
|
|
m_Player->SendAuxPlayer();
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else if(InvMo.ToInv == 4) //selling cargo
|
|
{
|
|
if (Source.ItemTemplateID < 0) // Keeps down XP hacking
|
|
break;
|
|
|
|
ItemBase * myItem = g_ItemBaseMgr->GetItem(Source.ItemTemplateID);
|
|
|
|
if (!myItem || myItem->TechLevel() > 9) //not allowed to sell items of level 10 or above to vendors (fixes grail water XP hack).
|
|
break;
|
|
|
|
if (Source.StackCount <= InvMo.Num)
|
|
{
|
|
Destination = g_ItemBaseMgr->EmptyItem;
|
|
}
|
|
else
|
|
{
|
|
Destination = Source;
|
|
Destination.StackCount -= InvMo.Num;
|
|
Destination.TradeStack -= InvMo.Num;
|
|
}
|
|
|
|
char msg_buffer[128];
|
|
|
|
// something VERY simple and yet efficient
|
|
long XP_earned = 50 * myItem->TechLevel() * (Source.TradeStack < InvMo.Num ? Source.TradeStack : InvMo.Num);
|
|
|
|
sprintf(msg_buffer, "You have gained %ld credits", Source.Price * InvMo.Num);
|
|
|
|
if (XP_earned > 0)
|
|
{
|
|
char sub_buffer[40];
|
|
sprintf(sub_buffer, " and %ld trade experience", XP_earned);
|
|
strcat(msg_buffer, sub_buffer);
|
|
}
|
|
|
|
SendMessageString(msg_buffer, 3);
|
|
SendClientSound("coin.wav");
|
|
|
|
if (XP_earned > 0)
|
|
{
|
|
sprintf(msg_buffer, "Item(s) eligible for");
|
|
AddTradeXP(msg_buffer, XP_earned);
|
|
}
|
|
|
|
m_Player->PlayerIndex()->SetCredits(m_Player->PlayerIndex()->GetCredits() + Source.Price * InvMo.Num);
|
|
m_Player->SendAuxPlayer();
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else if(InvMo.ToInv == 11) //spaceing item
|
|
{
|
|
Destination = Source;
|
|
Destination.StackCount -= InvMo.Num;
|
|
|
|
if (Destination.StackCount <= 0)
|
|
{
|
|
Destination = g_ItemBaseMgr->EmptyItem;
|
|
}
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
// Result box in Manufacturing
|
|
else if(InvMo.ToInv == 12 && (m_Player->ManuIndex()->GetMode() == 2 || m_Player->ManuIndex()->GetMode() == 3))
|
|
{
|
|
Destination = *m_Player->ManuIndex()->Target.Item[0].GetData();
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->ManuIndex()->Target.Item[0].SetData(&Source);
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
// Control Interface box in Manufacturing
|
|
else if(InvMo.ToInv == 14 && m_Player->ManuIndex()->GetMode() != 4)
|
|
{
|
|
Destination = *m_Player->ManuIndex()->Override.Item[0].GetData();
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->ManuIndex()->Override.Item[0].SetData(&Source);
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
else if(InvMo.ToInv == 16) //cargo to trade
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.TradeInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (m_TradeID == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Player * targetp;
|
|
targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
targetp->SendItemBase(Source.ItemTemplateID);
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->Connection()->TradeAction(0,6);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// From Equip Inventory
|
|
case 2:
|
|
Source = *m_Player->ShipIndex()->Inventory.EquipInv.EquipItem[InvMo.FromSlot].GetItemData();
|
|
|
|
if (InvMo.ToInv == 1) //unequip item
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (!m_Player->m_Equip[InvMo.FromSlot].CanEquip(&Destination))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Source = m_Player->m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else if(InvMo.ToInv == 2) //move equip item
|
|
{
|
|
//If one of these is Reactor, Engine or Shield, you cant move them
|
|
if (InvMo.FromSlot < 3 || InvMo.ToSlot < 3)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//If trying to move a weapon to device, or a device to weapon, prevent it
|
|
if ((InvMo.FromSlot < 9 && InvMo.ToSlot > 8) || (InvMo.FromSlot > 8 && InvMo.ToSlot < 9))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Destination = *m_Player->ShipIndex()->Inventory.EquipInv.EquipItem[InvMo.ToSlot].GetItemData();
|
|
|
|
//Moving two devices, just exchange them
|
|
if (InvMo.FromSlot > 8 || InvMo.ToSlot > 8)
|
|
{
|
|
Source = m_Player->m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
m_Player->m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
|
|
//Now we are exchanging two weapon slots, the problem is that they can have ammo
|
|
|
|
//If either weapon has ammo
|
|
if (m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetItemTemplateID() != -2 ||
|
|
m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.FromSlot].GetItemTemplateID() != -2)
|
|
{
|
|
//if the weapons are the same, swap the ammo in them, otherwise do nothing
|
|
if (Source.ItemTemplateID == Destination.ItemTemplateID)
|
|
{
|
|
Source = *m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.FromSlot].GetData();
|
|
Destination = *m_Player->ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Player->m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
m_Player->m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//If neither have ammo, just swap them normally
|
|
Source = m_Player->m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
m_Player->m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
|
|
m_Player->SendAuxShip();
|
|
}
|
|
break;
|
|
|
|
// From Vault Inventory
|
|
case 3:
|
|
Source = *m_Player->PlayerIndex()->SecureInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if (InvMo.ToInv == 1) //move from vault to cargo
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
else if(InvMo.ToInv == 3) //vault to vault
|
|
{
|
|
Destination = *m_Player->PlayerIndex()->SecureInv.Item[InvMo.ToSlot].GetData();
|
|
m_Player->CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Player->PlayerIndex()->SecureInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
else if(InvMo.ToInv == 11) //destroy item
|
|
{
|
|
Destination = Source;
|
|
Destination.StackCount -= InvMo.Num;
|
|
|
|
if (Destination.StackCount <= 0)
|
|
{
|
|
Destination = g_ItemBaseMgr->EmptyItem;
|
|
}
|
|
|
|
m_Player->PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
break;
|
|
|
|
// From Vendor Inventory
|
|
case 4:
|
|
|
|
Source = *m_Player->PlayerIndex()->VendorInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if (InvMo.ToInv == 1) //buy item
|
|
{
|
|
u64 Cost = Source.Price * InvMo.Num;
|
|
if (m_Player->PlayerIndex()->GetCredits() < Cost)
|
|
{
|
|
m_Player->SendVaMessage("Insufficient credits!");
|
|
return;
|
|
}
|
|
|
|
m_Player->PlayerIndex()->SetCredits(m_Player->PlayerIndex()->GetCredits() - Cost);
|
|
|
|
//take losses on resales to vendors
|
|
Cost /= 4;
|
|
|
|
Source.StackCount = InvMo.Num; // Trade this many items
|
|
|
|
m_Player->CargoAddItem(&Source);
|
|
m_Player->SendAuxPlayer();
|
|
m_Player->SendAuxShip();
|
|
}
|
|
break;
|
|
|
|
// From Loot Window
|
|
case 6:
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_HUSK:
|
|
m_Player->LootItem(InvMo.FromSlot);
|
|
break;
|
|
|
|
default:
|
|
LogMessage("Attempt to loot %s [%d]\n", obj->Name(), obj->GameID());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogMessage("Attempt to mine invalid object :%d\n", m_Player->ShipIndex()->GetTargetGameID());
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Manufacturing Target
|
|
case 12:
|
|
if (InvMo.ToInv == 1 && (m_Player->ManuIndex()->GetMode() == 2 || m_Player->ManuIndex()->GetMode() == 3))
|
|
{
|
|
Source = *m_Player->ManuIndex()->Target.Item[0].GetData();
|
|
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
m_Player->CargoAddItem(&Source);
|
|
m_Player->ManuIndex()->Target.Item[0].Empty();
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
else if (InvMo.ToInv == 1)
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->ManuIndex()->Target.Item[0].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Manufacturing Override
|
|
case 14:
|
|
if (InvMo.ToInv == 1 && m_Player->ManuIndex()->GetMode() != 4)
|
|
{
|
|
Source = *m_Player->ManuIndex()->Override.Item[0].GetData();
|
|
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
m_Player->CargoAddItem(&Source);
|
|
m_Player->ManuIndex()->Override.Item[0].Empty();
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
else if (InvMo.ToInv == 1)
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->ManuIndex()->Override.Item[0].SetData(&Destination);
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendAuxManu();
|
|
}
|
|
}
|
|
break;
|
|
|
|
// From Trade Window
|
|
case 16:
|
|
|
|
Source = *m_Player->ShipIndex()->Inventory.TradeInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if (InvMo.ToInv == 1 && InvMo.ToSlot > 0) //back to inventory
|
|
{
|
|
Destination = *m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (m_TradeID == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Player * targetp;
|
|
targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
targetp->SendItemBase(Source.ItemTemplateID);
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
m_Player->SendAuxShip();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->Connection()->TradeAction(0,6);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
// From Mining Window
|
|
case 18:
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_HUSK:
|
|
m_Player->LootItem(InvMo.FromSlot);
|
|
break;
|
|
|
|
case OT_HULK:
|
|
case OT_RESOURCE:
|
|
m_Player->MineResource(InvMo.FromSlot);
|
|
break;
|
|
|
|
default:
|
|
LogMessage("Attempt to loot/mine %s [%d]\n", obj->Name(), obj->GameID());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogMessage("Attempt to mine invalid object :%d\n", m_Player->ShipIndex()->GetTargetGameID());
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
LogMessage("UNRECOGNISED INVENTORY MOVE -- GameID: %ld From: %ld Slot: %ld To: %ld Slot %ld Number: %ld\n", InvMo.GameID,InvMo.FromInv,
|
|
InvMo.FromSlot, InvMo.ToInv, InvMo.ToSlot, InvMo.Num);
|
|
|
|
m_Player->SendVaMessage("UNRECOGNISED INVENTORY MOVE!\nPlease submit a bug report\n");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void Connection::HandleItemState()
|
|
{
|
|
ItemState * Data = (ItemState *) m_RecvBuffer;
|
|
|
|
if (Data->Inventory == 2)
|
|
{
|
|
long ItemState = m_Player->ShipIndex()->Inventory.EquipInv.EquipItem[Data->ItemNum].GetItemState();
|
|
|
|
if (Data->Enable == 1)
|
|
{
|
|
ItemState |= Data->BitMask;
|
|
}
|
|
else
|
|
{
|
|
ItemState &= ~Data->BitMask;
|
|
}
|
|
|
|
m_Player->ShipIndex()->Inventory.EquipInv.EquipItem[Data->ItemNum].SetItemState(ItemState);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
else
|
|
{
|
|
LogMessage("UNRECOGNISED ITEM STATE:\n");
|
|
DumpBuffer(m_RecvBuffer, sizeof(ItemState));
|
|
|
|
m_Player->SendVaMessage("UNRECOGNISED ITEM STATE!\nPlease submit a bug report\n");
|
|
}
|
|
}
|
|
|
|
void Connection::HandleRequestTarget()
|
|
{
|
|
RequestTarget * request = (RequestTarget *) m_RecvBuffer;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(request->TargetID);
|
|
|
|
//LogMessage("Received RequestTarget packet\n");
|
|
|
|
if (m_ProspectWindow == true)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
|
|
SendSetTarget(request->TargetID, -1);
|
|
|
|
if (obj->ObjectType() == OT_MOB)
|
|
{
|
|
// Display just Combat Level
|
|
m_Player->ShipIndex()->SetTargetThreatLevel(obj->Level());
|
|
} else {
|
|
if (obj->ObjectType() == OT_PLAYER) {
|
|
// Display just Text
|
|
m_Player->ShipIndex()->SetTargetThreatLevel(-1);
|
|
m_Player->ShipIndex()->SetTargetThreat("Not Working Yet");
|
|
} else {
|
|
// Display nothing
|
|
m_Player->ShipIndex()->SetTargetThreatLevel(-1);
|
|
m_Player->ShipIndex()->SetTargetThreat("");
|
|
}
|
|
}
|
|
|
|
m_Player->ShipIndex()->SetTargetThreatSound("success_1.wav");
|
|
m_Player->ShipIndex()->SetTargetGameID(request->TargetID);
|
|
m_Player->SendAuxShip();
|
|
m_Player->BlankVerbs();
|
|
|
|
if (obj)
|
|
{
|
|
obj->OnTargeted(m_Player);
|
|
}
|
|
}
|
|
|
|
void Connection::HandleRequestTargetsTarget()
|
|
{
|
|
RequestTarget * request = (RequestTarget *) m_RecvBuffer;
|
|
Player *p = m_ServerMgr.m_PlayerMgr.GetPlayer(request->TargetID);
|
|
|
|
if (p && p->Connection())
|
|
{
|
|
*((int *) &m_RecvBuffer[4]) = p->ShipIndex()->GetTargetGameID();
|
|
HandleRequestTarget();
|
|
}
|
|
else
|
|
{
|
|
SendSetTarget(0, -1);
|
|
m_Player->ShipIndex()->SetTargetGameID(-1);
|
|
m_Player->SendAuxShip();
|
|
}
|
|
}
|
|
|
|
bool Connection::CheckResourceLock(long object_id)
|
|
{
|
|
char * player = 0;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(object_id);
|
|
|
|
if (obj)
|
|
{
|
|
player = obj->CheckResourceLock();
|
|
}
|
|
|
|
if (player)
|
|
{
|
|
m_Player->SendVaMessage("%s is being mined by %s", obj->Name(), player);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
long Connection::CurrentResourceTarget()
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
return (m_Player->ShipIndex()->GetTargetGameID());
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void Connection::HandleVerbRequest()
|
|
{
|
|
//Here is a list of VerbID's for HUD icons:
|
|
//01 - scan; 02 - land; 03 - loot
|
|
//04 - group; 05 - message; 06 - trade
|
|
//07 - tractor; 08 - Dock; 09 - Prospect
|
|
//0a - gate; 0b - register 0c - jumpstart
|
|
//0d - follow
|
|
|
|
//And Attributes:
|
|
//00 - Enabled (all others disabled)
|
|
//01 - Player already in group
|
|
//02 - Too far
|
|
//03+ - Unavailable -- Disabled with no reason given
|
|
|
|
VerbRequest * pkt = (VerbRequest *) m_RecvBuffer;
|
|
|
|
long subject_id = (long) ntohl(pkt->SubjectID);
|
|
long object_id = (long) ntohl(pkt->ObjectID);
|
|
|
|
//LogMessage("Received VerbRequest packet {SubjectID=%d, ObjectID=%d, Action=%d}\n",
|
|
// subject_id, object_id, pkt->Action);
|
|
|
|
if (subject_id == m_AvatarID && pkt->Action == 1)
|
|
{
|
|
m_Player->UpdateVerbs(true);
|
|
}
|
|
}
|
|
|
|
//This is just used to tweak HUD verbs for the /verb command
|
|
void Connection::HandleSendVerbRequest(char *param)
|
|
{
|
|
short verbID = _httoi(param);
|
|
|
|
//SendVerbUpdatePacket(m_Player->ShipIndex()->GetTargetGameID(), ATTRIBUTE_DIS_TOOFAR, 0, verbID, 0, 0, 0);
|
|
}
|
|
|
|
void Connection::OpenInterface(long UIChange, long UIType)
|
|
{
|
|
SetInterface set_interface;
|
|
set_interface.UIChange = UIChange;
|
|
set_interface.UIType = UIType;
|
|
|
|
//LogMessage("Sending SetInterface packet\n");
|
|
SendResponse(ENB_OPCODE_0066_OPEN_INTERFACE, (unsigned char *) &set_interface, sizeof(set_interface));
|
|
}
|
|
|
|
void Connection::CloseInterfaceIfTargetted(long target_id)
|
|
{
|
|
if (m_Player->ShipIndex()->GetTargetGameID() == target_id)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
}
|
|
|
|
void Connection::CloseInterfaceIfOpen()
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
}
|
|
|
|
void Connection::PointEffect(float *position, short effect_id, float scale)
|
|
{
|
|
/*2C 00 Length = 44 bytes
|
|
0A 00 Opcode 0x0A = Point_Effect
|
|
BF 0C 3A 00 object_id
|
|
24 6A 7E 25 time+200
|
|
18 E4 CA C7 x
|
|
B5 05 19 47 y
|
|
F6 50 98 45 z
|
|
00 00 duration
|
|
F5 03 effect_id
|
|
7A FB 01 43 scale
|
|
00 00 00 00 H
|
|
00 00 00 00 S
|
|
00 00 00 00 V */
|
|
|
|
unsigned char point_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00, //0
|
|
0x00, 0x00, 0x00, 0x00, //4
|
|
0x00, 0x00, 0x00, 0x00, //8
|
|
0x01, 0x00, 0x00, 0x00, //12
|
|
0x59, 0x0B, 0x00, 0x00, //16
|
|
0x64, 0x4C, //20
|
|
0x20, 0x25, //22
|
|
0x00, 0x00, 0x00, 0x00, //24
|
|
0x00, 0x00, 0x00, 0x00, //28
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
*((long *) &point_data[0]) = m_SectorMgr->GetSectorNextObjID();
|
|
*((long *) &point_data[4]) = GetNet7TickCount() + 200;
|
|
*((float *) &point_data[8]) = position[0];
|
|
*((float *) &point_data[12]) = position[1];
|
|
*((float *) &point_data[16]) = position[2];
|
|
*((short *) &point_data[20]) = 0;
|
|
*((short *) &point_data[22]) = effect_id;
|
|
*((float *) &point_data[24]) = 129.982f * scale;
|
|
|
|
SendResponse(ENB_OPCODE_000A_POINT_EFFECT, point_data, sizeof(point_data));
|
|
}
|
|
|
|
void Connection::SendAttackerUpdates(long mob_id, long update)
|
|
{
|
|
unsigned char attacker_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x01,
|
|
0x00, 0x00, 0x00, 0x00 //[5]
|
|
};
|
|
|
|
*((long *) &attacker_data[0]) = update;
|
|
*((long *) &attacker_data[5]) = mob_id;
|
|
|
|
SendResponse(ENB_OPCODE_008B_ATTACKER_UPDATES, attacker_data, sizeof(attacker_data));
|
|
}
|
|
void Connection::SendChangeBasset(ChangeBaseAsset *NewAsset)
|
|
{
|
|
SendResponse(ENB_OPCODE_0026_CHANGE_BASE_ASSET, (unsigned char*) NewAsset, sizeof(ChangeBaseAsset));
|
|
}
|
|
|
|
void Connection::SendObjectLinkedEffect(short bitmask, long UID, long effectID, short effectDID, long effect_time)
|
|
{
|
|
//send an effect linked to our ship
|
|
ObjectToObjectEffect OBTOBE;
|
|
|
|
OBTOBE.Bitmask = bitmask;
|
|
OBTOBE.GameID = m_AvatarID;
|
|
OBTOBE.TargetID = UID;
|
|
OBTOBE.EffectDescID = effectDID;
|
|
OBTOBE.Message = 0;
|
|
OBTOBE.EffectID = effectID;
|
|
OBTOBE.Duration = short(effect_time);
|
|
OBTOBE.TimeStamp = GetNet7TickCount();
|
|
|
|
SendObjectToObjectEffect(&OBTOBE);
|
|
}
|
|
|
|
void Connection::CheckObjectRanges()
|
|
{
|
|
if (this && m_Player->ConnectionAvailable())
|
|
{
|
|
m_ObjectMgr->DisplayDynamicObjects(m_Player);
|
|
}
|
|
}
|
|
|
|
void Connection::SendClientSound(char *sound_name, long channel, char queue)
|
|
{
|
|
unsigned char packet[128];
|
|
memset(packet,0,128);
|
|
int index = 0;
|
|
|
|
long length = strlen(sound_name) + 1;
|
|
|
|
AddData(packet, length, index);
|
|
AddDataS(packet, sound_name, index);
|
|
AddData(packet, char(0), index);
|
|
AddData(packet, channel, index);
|
|
AddData(packet, queue, index);
|
|
|
|
SendResponse(ENB_OPCODE_006A_CLIENT_SOUND, (unsigned char *) &packet[0], index);
|
|
}
|
|
|
|
void Connection::SendSetTarget(int game_id, int target_id)
|
|
{
|
|
SetTarget set_target;
|
|
set_target.GameID = game_id;
|
|
set_target.TargetID = target_id;
|
|
|
|
SendResponse(ENB_OPCODE_0019_SET_TARGET, (unsigned char *) &set_target, sizeof(set_target));
|
|
}
|
|
|
|
void Connection::SendRemoveEffect(int target_id)
|
|
{
|
|
SendResponse(ENB_OPCODE_000F_REMOVE_EFFECT, (unsigned char *) &target_id, sizeof(int));
|
|
}
|
|
|
|
void Connection::TradeAction(long GameID, int Action)
|
|
{
|
|
unsigned char buffer[5];
|
|
|
|
*((long *) &buffer[0]) = GameID;
|
|
*((char *) &buffer[4]) = (char) Action;
|
|
|
|
SendResponse(ENB_OPCODE_001F_TRADE, buffer, 5);
|
|
}
|
|
|
|
void Connection::HandleAction()
|
|
{
|
|
ActionPacket * myAction = (ActionPacket *) m_RecvBuffer;
|
|
char message[128];
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
LogDebug("Action - ID: %d, Action: %d, Target: %d, OptVar: %d\n",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
|
|
int x;
|
|
|
|
switch (myAction->Action)
|
|
{
|
|
case 1: //tractor
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to tractor while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj)
|
|
{
|
|
//shouldnt targeted ID be myAction->target??
|
|
//you would thinkthat, but for some reason HULK action doesn't send the target ID...
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_FLOATING_ORE:
|
|
m_Player->LootItem(0);
|
|
break;
|
|
|
|
case OT_HUSK:
|
|
if (m_ProspectWindow == false && CheckResourceLock(m_Player->ShipIndex()->GetTargetGameID()))
|
|
{
|
|
SendResourceContentsAUX(obj);
|
|
m_ProspectWindow = true;
|
|
OpenInterface(0, 0);
|
|
SendMessageString("\0", 17);
|
|
}
|
|
else
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case 7: //docking complete
|
|
if (obj)
|
|
{
|
|
long destination = obj->Destination();
|
|
if (destination == 0)
|
|
{
|
|
destination = m_SectorMgr->GetSectorID() * 10 + 1;
|
|
//LogMessage("TODO: Stations should have destinations in DASE: some sectors have more than 1 station.\n");
|
|
}
|
|
m_SectorMgr->SectorServerHandoff(this, destination);
|
|
break;
|
|
}
|
|
case 8: //land
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to land while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj)
|
|
{
|
|
if (obj->Destination() > 0)
|
|
{
|
|
// Cancel trade if docking
|
|
if (m_TradeID != -1)
|
|
CancelTrade();
|
|
|
|
m_Player->TerminateWarp();
|
|
m_SectorMgr->SectorServerHandoff(this, obj->Destination());
|
|
LogMessage("going to planet : %d\n", obj->Destination());
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 9: //fire all weapons
|
|
{
|
|
// if you are incapacited you cant equip items
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to fire weapons while incapacitated.", 11);
|
|
return;
|
|
}
|
|
m_Player->FireAllWeapons();
|
|
break;
|
|
}
|
|
case 10: //invite target to group
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.GroupInvite(m_Player->GroupID(),m_AvatarID,myAction->Target);
|
|
break;
|
|
}
|
|
case 11: //accept group invitation
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.AcceptGroupInvite(m_Player->GroupID(),m_AvatarID);
|
|
break;
|
|
}
|
|
case 12: //decline group invitation
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.RejectGroupInvite(m_Player->GroupID(), m_AvatarID);
|
|
break;
|
|
}
|
|
case 13: //disban group
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.DisbanGroup(m_Player->GroupID(), m_AvatarID);
|
|
break;
|
|
}
|
|
case 14: //leave group
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.LeaveGroup(m_Player->GroupID(), m_AvatarID);
|
|
break;
|
|
}
|
|
case 15: //kick target from group
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.KickFromGroup(m_Player->GroupID(), m_AvatarID, myAction->Target);
|
|
break;
|
|
}
|
|
case 17: //mine
|
|
{
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to mine while incapacitated.", 11);
|
|
return;
|
|
}
|
|
//if window open close it
|
|
if (m_ProspectWindow)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
break;
|
|
}
|
|
|
|
if (obj != 0 && (obj->ObjectType() == OT_RESOURCE || obj->ObjectType() == OT_HULK) &&
|
|
CheckResourceLock(myAction->Target))
|
|
{
|
|
m_ProspectWindow = true;
|
|
OpenInterface(0,0);
|
|
SendMessageString("\0", 17);
|
|
}
|
|
break;
|
|
}
|
|
case 18: //gate button
|
|
{
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to gate while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj != 0 && obj->ObjectType() == OT_STARGATE)
|
|
{
|
|
m_Player->TerminateWarp();
|
|
SendClientSound("1512_00_032Se.mp3",0,0);
|
|
m_SectorMgr->GateActivate(this, myAction->Target);
|
|
}
|
|
break;
|
|
}
|
|
case 19: //finish gate sequence
|
|
{
|
|
m_SectorMgr->SectorServerHandoff(this, m_StargateDestination);
|
|
}
|
|
break;
|
|
|
|
//TODO: Remove confirm if trade changes
|
|
case 20: //trade
|
|
{
|
|
Player * targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(myAction->Target);
|
|
if (targetp)
|
|
{
|
|
if (targetp->Connection()->m_TradeID != -1)
|
|
{
|
|
m_Player->SendVaMessage("That player is already trading with someone!");
|
|
}
|
|
|
|
LogMessage("Clearing trade for players %x and %x\n",myAction->GameID,myAction->Target);
|
|
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->SendAuxShip(m_Player);
|
|
|
|
// TESTING
|
|
if (!m_Player->Active() && myAction->Target != m_Player->GameID())
|
|
{
|
|
SendCreate(targetp->GameID(), 1, 0x4B06, CREATE_SHIP, 0, 0, 0);
|
|
targetp->Connection()->SendCreate(m_Player->GameID(), 1, 0x4B06, CREATE_SHIP, 0, 0, 0);
|
|
}
|
|
// -------
|
|
|
|
TradeAction(myAction->Target,0); // Opens a trade window
|
|
targetp->Connection()->TradeAction(myAction->GameID, 0); // Open trade window for other player
|
|
m_TradeID = myAction->Target; // Set player tradeing with
|
|
m_TradeConferm = 0;
|
|
targetp->Connection()->m_TradeID = myAction->GameID;
|
|
targetp->Connection()->m_TradeConferm = 0;
|
|
}
|
|
}
|
|
break;
|
|
case 21: //confirm trade
|
|
{
|
|
Player * targetp;
|
|
targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(m_TradeID);
|
|
m_TradeConferm = 1;
|
|
TradeAction(0,3);
|
|
|
|
if (targetp)
|
|
{
|
|
targetp->Connection()->TradeAction(0,5);
|
|
}
|
|
|
|
if (targetp && targetp->Connection()->m_TradeConferm == 1)
|
|
{
|
|
LogMessage("Trade comfirned for players %x and %x\n",myAction->GameID,myAction->Target);
|
|
|
|
//close windows and reset tradeIds
|
|
TradeAction(m_TradeID,2);
|
|
targetp->Connection()->TradeAction(myAction->GameID, 2);
|
|
m_TradeID = -1;
|
|
targetp->Connection()->m_TradeID = -1;
|
|
|
|
//add and remove credits
|
|
m_Player->PlayerIndex()->SetCredits(m_Player->PlayerIndex()->GetCredits() + targetp->ShipIndex()->GetTradeMoney() - m_Player->ShipIndex()->GetTradeMoney());
|
|
m_Player->SendAuxPlayer();
|
|
targetp->PlayerIndex()->SetCredits(targetp->PlayerIndex()->GetCredits() + m_Player->ShipIndex()->GetTradeMoney() - targetp->ShipIndex()->GetTradeMoney());
|
|
targetp->SendAuxPlayer();
|
|
|
|
//Add other player's items
|
|
for(x=0;x<6;x++)
|
|
{
|
|
m_Player->CargoAddItem(targetp->ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
m_Player->SendAuxShip();
|
|
|
|
//add items to other player
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->CargoAddItem(m_Player->ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
targetp->SendAuxShip();
|
|
|
|
//clear trade fr both players
|
|
LogMessage("Clearing trade for players %x and %x\n",myAction->GameID,myAction->Target);
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->SendAuxShip(m_Player);
|
|
|
|
// Reset money
|
|
targetp->ShipIndex()->SetTradeMoney(0);
|
|
m_Player->ShipIndex()->SetTradeMoney(0);
|
|
|
|
|
|
// TESTING
|
|
if (!m_Player->Active() && myAction->Target != m_Player->GameID()) // if we are in a station use this
|
|
{
|
|
RemoveObject(targetp->GameID());
|
|
targetp->Connection()->RemoveObject(m_Player->GameID());
|
|
}
|
|
// ----
|
|
}
|
|
}
|
|
break;
|
|
case 22: //cancel trade
|
|
{
|
|
CancelTrade();
|
|
}
|
|
break;
|
|
case 23: //keep trading???
|
|
{
|
|
m_Player->SendVaMessage("ACTION 23. Target: %d",myAction->Target);
|
|
break;
|
|
}
|
|
case 24: //trade money
|
|
{
|
|
// TODO: We need to log all player trades for the GMs
|
|
Player * targetp;
|
|
targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
m_Player->ShipIndex()->SetTradeMoney(myAction->OptionalVar);
|
|
m_Player->SendAuxShip(targetp);
|
|
m_Player->SendAuxShip();
|
|
m_Player->Connection()->TradeAction(m_TradeID,4);
|
|
targetp->Connection()->TradeAction(m_TradeID,4);
|
|
}
|
|
}
|
|
break;
|
|
case 25: //register
|
|
if (obj)
|
|
{
|
|
//Starbase Registration
|
|
if (obj->ObjectType() == OT_STATION && !m_RegistrationSent)
|
|
{
|
|
SendClientSound("Reg_OK",0,0);
|
|
sprintf(&message[0],"%s control: Registration Confirmed.", obj->Name());
|
|
SendMessageString(message,5);
|
|
|
|
m_Player->PlayerIndex()->SetRegistrationStarbase(obj->Name());
|
|
m_Player->PlayerIndex()->SetRegistrationStarbaseSector(m_Player->PlayerIndex()->GetSectorName());
|
|
m_RegistrationSent = true;
|
|
}
|
|
break;
|
|
}
|
|
case 26: // Jump Start
|
|
if (!obj)
|
|
{
|
|
m_Player->SendVaMessage("Invalid JS target! SUBMIT BUG REPORT!");
|
|
return;
|
|
}
|
|
|
|
if (obj->ObjectType() == OT_PLAYER)
|
|
{
|
|
m_Player->AbilityJumpStart(obj->GameID());
|
|
}
|
|
break;
|
|
case 28: //dock
|
|
// if you are incapacited you cant equip items
|
|
if (m_Player->ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to dock while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj)
|
|
{
|
|
if (obj->ObjectType() == OT_STATION)
|
|
{
|
|
if (m_TradeID != -1)
|
|
{
|
|
CancelTrade();
|
|
}
|
|
m_SectorMgr->Dock(this, obj->GameID());
|
|
}
|
|
break;
|
|
}
|
|
case 29: //planet landing button
|
|
{
|
|
SendClientSound("1512_00_032Se.mp3",0,0);
|
|
break;
|
|
}
|
|
case 30: //scan object in space
|
|
{
|
|
long UID = m_SectorMgr->GetSectorNextObjID();
|
|
m_Player->SendEffect(obj->GameID(), 0, 10007, UID, GetNet7TickCount(), 3000);
|
|
//by default when you scan something you cause a mission advance
|
|
m_Player->MissionObjectScan(obj);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
LogMessage("UNRECOGNIZED ACTION! ID: %d, Action: %d, Target: %d, OptVar: %d\n",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
m_Player->SendVaMessage("UNRECOGNIZED ACTION! SUBMIT BUG REPORT!");
|
|
m_Player->SendVaMessage("Action ID: %d, Action: %d, Target: %d, OptVar: %d",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Connection::CancelTrade()
|
|
{
|
|
Player * targetp;
|
|
targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
LogMessage("Trade cancelled for players %x and %x\n", m_Player->GameID(), m_TradeID);
|
|
|
|
TradeAction(m_TradeID,1); // Closes a trade window
|
|
targetp->Connection()->TradeAction(m_Player->GameID(), 1); // Closes trade window for other player
|
|
m_TradeID = -1; // No longer Tradeing
|
|
targetp->Connection()->m_TradeID = -1;
|
|
|
|
//return player's items
|
|
for(int x=0;x<6;x++)
|
|
{
|
|
m_Player->CargoAddItem(m_Player->ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
m_Player->SendAuxShip();
|
|
|
|
//return other player's items
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->CargoAddItem(targetp->ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
targetp->SendAuxShip();
|
|
|
|
//clear trade fr both players
|
|
LogMessage("Clearing trade for players %x and %x\n", m_Player->GameID(), m_TradeID);
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->SendAuxShip(m_Player);
|
|
|
|
targetp->Connection()->m_TradeConferm = 0;
|
|
m_TradeConferm = 0;
|
|
|
|
// Reset money
|
|
targetp->ShipIndex()->SetTradeMoney(0);
|
|
m_Player->ShipIndex()->SetTradeMoney(0);
|
|
|
|
// TESTING
|
|
if (!m_Player->Active() && m_TradeID != m_Player->GameID())
|
|
{
|
|
RemoveObject(targetp->GameID());
|
|
targetp->Connection()->RemoveObject(m_Player->GameID());
|
|
}
|
|
// ----
|
|
}
|
|
}
|
|
|
|
void Connection::SendResourceLevel(long target_id)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(target_id);
|
|
float resource_remains;
|
|
|
|
if (obj)
|
|
{
|
|
resource_remains = obj->ResourceRemains();//m_SectorMgr->CalcResourceRemains(obj);
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x0C, 0x00,
|
|
0x01,
|
|
0xC6, 0x02,
|
|
0x05,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
*((long *) aux_data) = target_id;
|
|
*((float *) &aux_data[10]) = resource_remains;
|
|
*((long *) &aux_data[14]) = obj->Level();
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
}
|
|
|
|
/*
|
|
void Connection::SendResourceContentsAUXForHulk(Object *obj)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (obj)
|
|
{
|
|
contents_already_sent = obj->GetIndex(m_Player->ResourceSendList());
|
|
|
|
if (!contents_already_sent)
|
|
{
|
|
unsigned char aux_data[] = //NB this only supports 4 ores in the resource inventory
|
|
{
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x3A, 0x01,
|
|
0x01,
|
|
0xA6, 0x02, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F,
|
|
0x36, 0x00, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x36, 0x00, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x36, 0x00, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x36, 0x00, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0x00, 0x00, 0x00, 0x00 //resource tech level
|
|
};
|
|
short entries = 0;
|
|
int index = 0;
|
|
ContentSlot *slot;
|
|
bool client_already_has_itembase = false;
|
|
for (int x = 0; x < MAX_ITEMS_PER_RESOURCE; x++)
|
|
{
|
|
slot = obj->GetContents(x);
|
|
if (slot->stack > 0 && slot->item)
|
|
{
|
|
index = 23 + x*11;
|
|
|
|
*((long *) &aux_data[index]) = slot->item->m_ItemTemplateID;
|
|
*((long *) &aux_data[index+4]) = slot->stack;
|
|
slot->item->SendItemBasePacket(this);
|
|
entries++;
|
|
}
|
|
}
|
|
|
|
*((long *) aux_data) = obj->GameID();
|
|
*((long *) &aux_data[316]) = obj->Level();
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
obj->SetIndex(m_Player->ResourceSendList());
|
|
}
|
|
}
|
|
}*/
|
|
|
|
//TODO: make this part of AUX handler.
|
|
void Connection::SendResourceContentsAUX(Object *obj)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (obj)
|
|
{
|
|
contents_already_sent = obj->GetIndex(m_Player->ResourceSendList());
|
|
|
|
if (!contents_already_sent)
|
|
{
|
|
unsigned char spacer[4] =
|
|
{
|
|
0x36, 0x00, 0xFF
|
|
};
|
|
unsigned char filler[8] =
|
|
{
|
|
0x16, 0x80, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF //6
|
|
};
|
|
unsigned char prologue[16] =
|
|
{
|
|
0x3A, 0x01,
|
|
0x01,
|
|
0xA6, 0x02, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F //15
|
|
};
|
|
|
|
unsigned char packet[340];
|
|
|
|
int index = 0;
|
|
ContentSlot *slot;
|
|
|
|
AddData(packet, obj->GameID(), index);
|
|
AddBuffer(packet, prologue, 16, index);
|
|
|
|
int x;
|
|
for (x = 0; x < MAX_ITEMS_PER_RESOURCE; x++)
|
|
{
|
|
slot = obj->GetContents(x);
|
|
if (slot->stack > 0 && slot->item)
|
|
{
|
|
AddBuffer(packet, spacer, 3, index);
|
|
AddData(packet, slot->item->ItemTemplateID(), index);
|
|
AddData(packet, long(slot->stack), index);
|
|
m_Player->SendItemBase(slot->item->ItemTemplateID());
|
|
}
|
|
else
|
|
{
|
|
AddBuffer(packet, filler, 7, index);
|
|
}
|
|
}
|
|
|
|
for (x = 0; x < 32; x++)
|
|
{
|
|
AddBuffer(packet, filler, 7, index);
|
|
}
|
|
|
|
AddData(packet, (long)obj->Level(), index);
|
|
|
|
//set length
|
|
*((short *) &packet[4]) = index-10;
|
|
|
|
SendResponse(ENB_OPCODE_001B_AUX_DATA, packet, index);
|
|
obj->SetIndex(m_Player->ResourceSendList());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::SendCameraControl(long Message, long GameID)
|
|
{
|
|
CameraControl data;
|
|
data.Message = Message;
|
|
data.GameID = GameID;
|
|
|
|
//LogMessage("Sending CameraControl packet\n");
|
|
SendResponse(ENB_OPCODE_0092_CAMERA_CONTROL, (unsigned char *) &data, sizeof(data));
|
|
}
|
|
|
|
bool Connection::MatchOptWithParam (char *option, char *arg, char *¶m, bool &msg_sent)
|
|
{
|
|
int len = strlen(option);
|
|
|
|
if (strncmp(option, arg, len) == 0)
|
|
{
|
|
if (arg[len] == '=' || arg[len] == ' ')
|
|
{
|
|
param = arg + len + 1;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Missing arg for option %s", option);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Quat4fMul(float vector1[], float vector2[], float *vector3)
|
|
{
|
|
float x1,y1,z1,w1,x2,y2,z2,w2;
|
|
|
|
w1 = vector1[3];
|
|
x1 = vector1[0];
|
|
y1 = vector1[1];
|
|
z1 = vector1[2];
|
|
|
|
w2 = vector2[3];
|
|
x2 = vector2[0];
|
|
y2 = vector2[1];
|
|
z2 = vector2[2];
|
|
|
|
vector3[3] = (w1*w2 - x1*x2 - y1*y2 - z1*z2);
|
|
vector3[0] = (w1*x2 + x1*w2 + y1*z2 - z1*y2);
|
|
vector3[1] = (w1*y2 - x1*z2 + y1*w2 + z1*x2);
|
|
vector3[2] = (w1*z2 + x1*y2 - y1*x2 + z1*w2);
|
|
|
|
}
|
|
|
|
//Object
|
|
void Quat4fMulInv(float vector1[], float vector2[], float *vector3)
|
|
{
|
|
float x1,y1,z1,w1,x2,y2,z2,w2;
|
|
|
|
w1 = vector1[3];
|
|
x1 = vector1[0];
|
|
y1 = vector1[1];
|
|
z1 = vector1[2];
|
|
|
|
w2 = vector2[3];
|
|
x2 = - vector2[0];
|
|
y2 = - vector2[1];
|
|
z2 = - vector2[2];
|
|
|
|
vector3[3] = (w1*w2 - x1*x2 - y1*y2 - z1*z2);
|
|
vector3[0] = (w1*x2 + x1*w2 + y1*z2 - z1*y2);
|
|
vector3[1] = (w1*y2 - x1*z2 + y1*w2 + z1*x2);
|
|
vector3[2] = (w1*z2 + x1*y2 - y1*x2 + z1*w2);
|
|
}
|
|
|
|
void Connection::HandleEquipUse()
|
|
{
|
|
EquipUse *myUse = (EquipUse *) m_RecvBuffer;
|
|
|
|
m_Player->m_Equip[myUse->InvSlot].ManualActivate();
|
|
}
|
|
|
|
void Connection::SendClientDamage(long target_id, long source_id, float damage, float modifier, long type, long inflicted)
|
|
{
|
|
int index = 0;
|
|
unsigned char packet[32];
|
|
|
|
AddData(packet, damage, index);
|
|
AddData(packet, modifier, index);
|
|
AddData(packet, type, index);
|
|
AddData(packet, inflicted, index);
|
|
AddData(packet, source_id, index);
|
|
AddData(packet, target_id, index);
|
|
|
|
SendResponse(ENB_OPCODE_0064_CLIENT_DAMAGE, packet, index);
|
|
}
|
|
|
|
void Connection::Dialog(char *Stringd, int Type)
|
|
{
|
|
int Index = 0;
|
|
unsigned char Data[75];
|
|
|
|
*((short*) &Data[Index]) = strlen(Stringd) + 1; // String Size
|
|
Index+=2;
|
|
*((long*) &Data[Index]) = Type; // Type
|
|
Index+=4;
|
|
memcpy(&Data[Index], Stringd, strlen(Stringd) + 1); // copy the string
|
|
Index+=strlen(Stringd)+1;
|
|
|
|
SendResponse(0x62, (unsigned char *) &Data, Index);
|
|
}
|
|
|
|
bool Connection::HandleResetMaster()
|
|
{
|
|
//simulate a connection dropout for test purposes
|
|
ResetConnection();
|
|
return true;
|
|
}
|
|
|
|
void Connection::HandleClientChat()
|
|
{
|
|
bool success = false;
|
|
bool msg_sent = false;
|
|
|
|
ClientChat * chat = (ClientChat *) m_RecvBuffer;
|
|
char * types[] =
|
|
{
|
|
"To Target",
|
|
"To Group",
|
|
"To Guild",
|
|
"To Local Area",
|
|
"To Entire Sector"
|
|
};
|
|
|
|
LogDebug("Received ClientChat packet -- GameID=%d Type=%d (%s)\n",
|
|
chat->GameID, chat->Type, types[chat->Type]);
|
|
|
|
char *p = chat->String;
|
|
p += strlen(p) + 1;
|
|
short length = *((short *) p);
|
|
p += 2;
|
|
|
|
// Send to everyone
|
|
if ((chat->Type == 4) && (chat->String[0] != '/'))
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.ChatSendEveryone(chat->GameID, chat->String);
|
|
}
|
|
|
|
if ((chat->Type == 1) && m_Player)
|
|
{
|
|
if (m_Player->GroupID() != -1)
|
|
m_ServerMgr.m_PlayerMgr.GroupChat(m_Player->GroupID(),m_Player->Name(), chat->String);
|
|
else
|
|
m_Player->SendVaMessage("Error: You are not in a group!");
|
|
}
|
|
|
|
// TODO: Handle slash commands here
|
|
//
|
|
// - Add slash command '/opcode' to allow user to enter hex opcodes to be echoed
|
|
// back to the client application for opcode testing.
|
|
//
|
|
// -- interpret data as hex (-x) (default)
|
|
// -- interpret data as little endian integer data (-i) (-i2) (-i4)
|
|
// -- interpret data as big endian integer data (-I2) (-I4)
|
|
// -- interpret data as floating point data (-f)
|
|
//
|
|
// - (Navigation) /n int gameID, float signature, byte visited, int navtype, byte ishuge
|
|
// - (ConstPositionalUp) /c int gameID, float x, float y, float z
|
|
// - (Create Object) /o int gameID, float scale, short asset, int type, float x, float y, float x
|
|
// - (Remove Object) /e int gameID
|
|
//
|
|
|
|
//TODO: reformat this to remove C hacker style braces ('} else {') and other unreadable formatting
|
|
// the rest of the Net7 source code adheres to the new C++ style standard
|
|
// please change this to use Net7/C++ formatting style ASAP.
|
|
|
|
// This is for GM/DEV/ADMIN commands!
|
|
if (chat->String[0] == '/' && chat->String[1] == '/' && chat->String[2] != 0 && m_Player->AdminLevel() >= 50)
|
|
{
|
|
char *param;
|
|
char *pch = (char*)_alloca(strlen(&chat->String[2]));//copy to stack to avoid heap fragment
|
|
strcpy(pch, &chat->String[2]);
|
|
int retval = 0;
|
|
switch(*pch)
|
|
{
|
|
case 'a':
|
|
{
|
|
if (MatchOptWithParam("adduser", pch, param, msg_sent))
|
|
{
|
|
char *Username = strtok(param, " ");
|
|
char *Password = strtok(NULL, " ");
|
|
char *Access = strtok(NULL, " ");
|
|
|
|
if (!Username || !Password || !Access)
|
|
{
|
|
m_Player->SendVaMessage("Syntax: //adduser <username> <password> <access>");
|
|
return;
|
|
}
|
|
|
|
if (g_AccountMgr->AddUser(Username, Password, Access))
|
|
{
|
|
m_Player->SendVaMessage("Account %s / %s / %s Created", Username, Password, Access);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Account creation failed!");
|
|
}
|
|
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
{
|
|
if (strcmp(pch, "rstations") == 0)
|
|
{
|
|
// Remove old Data
|
|
delete [] m_ServerMgr.m_StationList;
|
|
m_ServerMgr.m_StationList = NULL;
|
|
char SectorID[10];
|
|
|
|
StationLoader StationsReload;
|
|
StationsReload.LoadStations();
|
|
|
|
m_ServerMgr.m_StationList = StationsReload.GetStationList();
|
|
|
|
sprintf(SectorID, "%d", m_SectorID);
|
|
HandleWormholeRequest(SectorID);
|
|
|
|
m_Player->SendVaMessage("Reloading Stations...");
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
{
|
|
if (MatchOptWithParam("setpassword", pch, param, msg_sent))
|
|
{
|
|
char *Username = strtok(param, " ");
|
|
char *Password = strtok(NULL, " ");
|
|
|
|
if (!Username || !Password)
|
|
{
|
|
m_Player->SendVaMessage("Syntax: //setpassword <username> <password>");
|
|
return;
|
|
}
|
|
|
|
g_AccountMgr->ChangePassword(Username, Password);
|
|
m_Player->SendVaMessage("Account %s password has been set to %s", Username, Password);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case 'g':
|
|
{
|
|
if (MatchOptWithParam("gmgetaccess", pch, param, msg_sent))
|
|
{
|
|
Player * target = g_PlayerMgr->GetPlayer(param);
|
|
if (!target)
|
|
{
|
|
m_Player->SendVaMessage("Player `%s` not found", param);
|
|
return;
|
|
}
|
|
|
|
m_Player->SendVaMessage("Access level for `%s` is %d", param, target->AdminLevel());
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("gmsetaccess", pch, param, msg_sent))
|
|
{
|
|
char *Username = strtok(param, " ");
|
|
char *Access = strtok(NULL, " ");
|
|
|
|
if (!Username || !Access)
|
|
{
|
|
m_Player->SendVaMessage("Syntax: //gmsetaccess <playername> <password>");
|
|
return;
|
|
}
|
|
|
|
Player * target = g_PlayerMgr->GetPlayer(Username);
|
|
if (!target)
|
|
{
|
|
m_Player->SendVaMessage("Player `%s` not found", Username);
|
|
return;
|
|
}
|
|
|
|
long new_access = atoi(Access);
|
|
|
|
// Can't promote over your level
|
|
if (new_access > m_Player->AdminLevel())
|
|
new_access = m_Player->AdminLevel();
|
|
|
|
// Can't demote someone above your access
|
|
if (g_AccountMgr->GetAccountStatus(target->AccountUsername()) > m_Player->AdminLevel())
|
|
{
|
|
m_Player->SendVaMessage("Can't change access for player above your access level");
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
g_AccountMgr->SetAccountStatus(target->AccountUsername(), new_access);
|
|
m_Player->SendVaMessage("Player %s has access set to %d", Username, new_access);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("gmskillpoints", pch, param, msg_sent))
|
|
{
|
|
char *Username = 0, *SSkillPoints = 0;
|
|
int SkillPoints;
|
|
|
|
Username = strtok(param, " ");
|
|
if (Username) {
|
|
SSkillPoints = strtok(NULL, " ");
|
|
if (SSkillPoints)
|
|
SkillPoints = atoi(SSkillPoints);
|
|
}
|
|
|
|
if (SSkillPoints)
|
|
{
|
|
Player * TargetP = m_ServerMgr.m_PlayerMgr.GetPlayer(Username);
|
|
|
|
if (!TargetP) {
|
|
m_Player->SendVaMessage("Player %s is not online", Username);
|
|
msg_sent = true;
|
|
success = true;
|
|
} else {
|
|
TargetP->PlayerIndex()->RPGInfo.SetSkillPoints(SkillPoints);
|
|
TargetP->LevelUpForSkills();
|
|
TargetP->UpdateSkills();
|
|
TargetP->SendAuxPlayer();
|
|
TargetP->SendVaMessage("You have gotten %d SkillPoints", SkillPoints);
|
|
m_Player->SendVaMessage("You have gave %s %d SkillPoints", Username, SkillPoints);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
} else {
|
|
m_Player->SendVaMessage("Syntax: //gmskillpoints <playername> <skillpoints>");
|
|
success = false;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("gmenableskills", pch, param, msg_sent))
|
|
{
|
|
char *PlayerName = strtok(param, " ");
|
|
|
|
if (!PlayerName) {
|
|
m_Player->SendVaMessage("Syntax: //gmenableskills <playername>");
|
|
msg_sent = true;
|
|
success = false;
|
|
} else {
|
|
Player * TargetP = m_ServerMgr.m_PlayerMgr.GetPlayer(PlayerName);
|
|
|
|
if (!TargetP) {
|
|
m_Player->SendVaMessage("Player %s is not online", PlayerName);
|
|
msg_sent = true;
|
|
success = true;
|
|
} else {
|
|
u32 Availability[4] = {4,0,0,1};
|
|
for (int i=0;i<64;i++)
|
|
{
|
|
if (TargetP->PlayerIndex()->RPGInfo.Skills.Skill[i].GetAvailability()[0] == 3)
|
|
{
|
|
TargetP->PlayerIndex()->RPGInfo.Skills.Skill[i].SetAvailability(Availability);
|
|
}
|
|
TargetP->SendAuxPlayer();
|
|
}
|
|
msg_sent = true;
|
|
success = true;
|
|
TargetP->SendVaMessage("Your skills are now enabled");
|
|
m_Player->SendVaMessage("Player %s had skills enabled", PlayerName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("gmplayerlevel", pch, param, msg_sent))
|
|
{
|
|
char *Username = 0, *SLevel = 0;
|
|
int Level = 0;
|
|
|
|
Username = strtok(param, " ");
|
|
if (Username) {
|
|
SLevel = strtok(NULL, " ");
|
|
if (SLevel)
|
|
Level = atoi(SLevel);
|
|
}
|
|
|
|
if (SLevel && Level <= 50)
|
|
{
|
|
Player * TargetP = m_ServerMgr.m_PlayerMgr.GetPlayer(Username);
|
|
|
|
if (!TargetP) {
|
|
m_Player->SendVaMessage("Player %s is not online", Username);
|
|
msg_sent = true;
|
|
success = true;
|
|
} else {
|
|
TargetP->PlayerIndex()->RPGInfo.SetCombatLevel(Level);
|
|
TargetP->PlayerIndex()->RPGInfo.SetTradeLevel(Level);
|
|
TargetP->PlayerIndex()->RPGInfo.SetExploreLevel(Level);
|
|
TargetP->LevelUpForSkills();
|
|
TargetP->UpdateSkills();
|
|
TargetP->SendAuxPlayer();
|
|
|
|
TargetP->SendVaMessage("Combat, Explore and Trade LVLs set to %d",Level);
|
|
m_Player->SendVaMessage("Player %s leveled to %d", Username, Level);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Syntax: //gmplayerlevel <playername> <level 1-50>");
|
|
msg_sent = true;
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// This is for normal commands
|
|
if ((chat->String[0] == '/') &&
|
|
(chat->String[1] != 0) && (!msg_sent || !success))
|
|
{
|
|
char *param;
|
|
char *pch = (char*)_alloca(strlen(&chat->String[1]));//copy to stack to avoid heap fragment
|
|
strcpy(pch, &chat->String[1]);
|
|
int retval = 0;
|
|
switch(*pch)
|
|
{
|
|
case 'a':
|
|
{
|
|
if (strcmp(pch, "authlevel") == 0)
|
|
{
|
|
m_Player->SendVaMessage("Authentication Level - Num: %d", m_Player->AdminLevel());
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (m_Player->AdminLevel() >= 80 && MatchOptWithParam("altweapon", pch, param, msg_sent)) //no error checking - server devs only
|
|
{
|
|
char *cmd = strtok(param, " ");
|
|
int weapon_id, bone_id;
|
|
if (cmd)
|
|
{
|
|
weapon_id = atoi(cmd);
|
|
cmd = strtok(NULL, " ");
|
|
}
|
|
|
|
if (cmd)
|
|
{
|
|
bone_id = atoi(cmd);
|
|
}
|
|
|
|
//m_Player->ChangeMountBoneName(weapon_id, bone_id);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (m_Player->AdminLevel() >= 80 && MatchOptWithParam("altname", pch, param, msg_sent)) //no error checking - server devs only
|
|
{
|
|
char *cmd = strtok(param, " ");
|
|
int weapon_id = 0;
|
|
if (cmd)
|
|
{
|
|
weapon_id = atoi(cmd);
|
|
cmd = strtok(NULL, " ");
|
|
}
|
|
|
|
if (cmd)
|
|
{
|
|
m_Player->ChangeMountBoneName(weapon_id, cmd);
|
|
m_Player->SendVaMessage("Change weapon id #%d to %s", weapon_id, cmd);
|
|
}
|
|
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
{
|
|
//BUFF for future reference
|
|
|
|
/*
|
|
if (MatchOptWithParam("buff", pch, param, msg_sent))
|
|
{
|
|
AuxShip::Buff myBuff;
|
|
memset(&myBuff,0,sizeof(AuxShip::Buff));
|
|
|
|
myBuff.Flags[0] = (char) 0xF2;
|
|
myBuff.Flags[1] = (char) 0x01;
|
|
sprintf(myBuff.BuffType,"Damage_Tactics");
|
|
myBuff.BuffRemovalTime = GetNet7TickCount() + 100000;
|
|
myBuff.IsPermanent = false;
|
|
myBuff.ElementsFlags = 0x12;
|
|
|
|
myBuff.Elements[0].Flags[0] = (char) 0xF2;
|
|
myBuff.Elements[0].Flags[1] = (char) 0x01;
|
|
myBuff.Elements[0].ExpirationTime = GetNet7TickCount() + 10000;
|
|
myBuff.Elements[0].IsActive = true;
|
|
sprintf(myBuff.Elements[0].SourceObject, "Lesser Psionic Shield");
|
|
strcpy(myBuff.Elements[0].SourceEntity, m_AuxShip.m_Name);
|
|
myBuff.Elements[0].Magnitude = atoi(param);
|
|
|
|
m_Player->SendVaMessage("Sending buff 0!\n");
|
|
m_AuxShip.SetBuff(this,&myBuff,0);
|
|
msg_sent = true;
|
|
}
|
|
*/
|
|
|
|
}
|
|
break;
|
|
case 'c':
|
|
{
|
|
if (MatchOptWithParam("ccamera", pch, param, msg_sent))
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
m_Player->SendVaMessage("Camera control: %x, %x", ntohl(atoi(param)), ntohl(obj->GameID()) );
|
|
if (atoi(param) != 4) //this would cause a crash
|
|
{
|
|
SendCameraControl( ntohl(atoi(param)), ntohl(obj->GameID()) ) ;
|
|
}
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
else if (MatchOptWithParam("changepassword", pch, param, msg_sent))
|
|
{
|
|
m_ServerMgr.m_AccountMgr->ChangePassword(m_Player->AccountUsername(), param);
|
|
m_Player->SendVaMessage("Your password has been changed to: `%s`", param);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("createitem", pch, param, msg_sent))
|
|
{
|
|
if (atoi(param) == 3052 && strcmp(m_Player->AccountUsername(), "Tienbau")) //temp lockout for testing
|
|
{
|
|
m_Player->SendVaMessage("Unable to create.");
|
|
}
|
|
else if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
int FreeSlot = m_Player->GetCargoSlotFromItemID(0, -1);;
|
|
|
|
if (FreeSlot == -1)
|
|
{
|
|
m_Player->SendVaMessage("No free slots in inventory free up space");
|
|
}
|
|
else
|
|
{
|
|
_Item myItem = g_ItemBaseMgr->EmptyItem;
|
|
|
|
char *ItemIDs = strtok(param, " ");
|
|
char *NumberS;
|
|
int Number;
|
|
|
|
if (ItemIDs)
|
|
{
|
|
NumberS = strtok(NULL, " ");
|
|
if (NumberS)
|
|
{
|
|
Number = atoi(NumberS);
|
|
}
|
|
else
|
|
{
|
|
Number = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Number = 1;
|
|
}
|
|
|
|
myItem.ItemTemplateID = atoi(ItemIDs);
|
|
myItem.StackCount = Number;
|
|
myItem.Price = 200;
|
|
myItem.Quality = 1;
|
|
myItem.Structure = 1;
|
|
|
|
m_Player->CargoAddItem(&myItem);
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendVaMessage("Item %d Created %d", atoi(ItemIDs), Number);
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("GM Only command.");
|
|
}
|
|
}
|
|
else if (MatchOptWithParam("createcredits", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
m_Player->PlayerIndex()->SetCredits(m_Player->PlayerIndex()->GetCredits() + _atoi64(param));
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("GM Only command.");
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
/*
|
|
else if (MatchOptWithParam("createmission", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
m_ServerMgr.m_Missions.givePlayerMission(this, atoi(param));
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("GM Only command.");
|
|
}
|
|
}
|
|
*/
|
|
else if (MatchOptWithParam("createmob", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM -> admin
|
|
{
|
|
success = HandleMobCreateRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("GM Only command.");
|
|
}
|
|
}
|
|
else if (MatchOptWithParam("create", pch, param, msg_sent))
|
|
{
|
|
success = HandleObjCreateRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else if (0 == strcmp("checklock", pch))
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
char *player = obj->CheckResourceLock();
|
|
if (player)
|
|
{
|
|
m_Player->SendVaMessage("Currently being mined/looted by %s", player);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Not being looted.");
|
|
}
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
case 'd' :
|
|
if (MatchOptWithParam("dialog", pch, param, msg_sent))
|
|
{
|
|
char *a = strtok(param, ",");
|
|
char *b = strtok(NULL, ",");
|
|
if (b)
|
|
{
|
|
Dialog(a,atoi(b));
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "debug") == 0
|
|
&& m_Player->AdminLevel() >= 80)
|
|
{
|
|
g_Debug = !g_Debug;
|
|
LogMessage("Debug mode is %s\n", g_Debug ? "ON" : "OFF");
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (MatchOptWithParam("deco", pch, param, msg_sent))
|
|
{
|
|
if (param)
|
|
{
|
|
short basset = atoi(param);
|
|
Object *obj = m_ObjectMgr->AddNewObject(OT_DECO);
|
|
obj->SetPosition(m_Player->Position());
|
|
obj->SetBasset(basset);
|
|
obj->SetSignature(30000.0f);
|
|
obj->SetOrientation(0,0,0,0);
|
|
obj->SetScale(1.0f);
|
|
m_CurrentDecoObj = obj;
|
|
LogMessage("Deco created at:\n %.2f, %.2f %.2f Basset %d\n", obj->PosX(), obj->PosY(), obj->PosZ(), basset);
|
|
}
|
|
else
|
|
{
|
|
LogMessage("/deco <basset>");
|
|
}
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
break;
|
|
case 'e' :
|
|
{
|
|
if (strcmp(pch, "enableskills") == 0)
|
|
{
|
|
u32 Availability[4] = {4,0,0,1};
|
|
for (int i=0;i<64;i++)
|
|
{
|
|
if (m_Player->PlayerIndex()->RPGInfo.Skills.Skill[i].GetAvailability()[0] == 3)
|
|
{
|
|
m_Player->PlayerIndex()->RPGInfo.Skills.Skill[i].SetAvailability(Availability);
|
|
}
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
if (MatchOptWithParam("effect", pch, param, msg_sent))
|
|
{
|
|
char *cmd = strtok(param, " ");
|
|
int EffectDID = 0, Length, count = 0;
|
|
if (cmd)
|
|
{
|
|
EffectDID = atoi(cmd);
|
|
cmd = strtok(NULL, " ");
|
|
count++;
|
|
}
|
|
if (cmd)
|
|
{
|
|
Length = atoi(cmd);
|
|
}
|
|
else
|
|
{
|
|
Length = 4000;
|
|
}
|
|
|
|
if (count == 1)
|
|
{
|
|
ObjectEffect WarpEffect;
|
|
|
|
WarpEffect.Bitmask = 0x07;
|
|
WarpEffect.EffectDescID = EffectDID;
|
|
WarpEffect.EffectID = m_SectorMgr->GetSectorNextObjID();;
|
|
WarpEffect.GameID = chat->GameID;
|
|
WarpEffect.Duration = Length;
|
|
WarpEffect.TimeStamp = GetNet7TickCount();
|
|
|
|
m_Player->SendObjectEffectToRangeList(&WarpEffect);
|
|
|
|
m_Player->SendVaMessage("Send Effect %d Disc: %d for %dms", WarpEffect.EffectID, EffectDID, Length);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("/effect <effect_desc_id> <length>");
|
|
}
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("effecto", pch, param, msg_sent))
|
|
{
|
|
char *cmd = strtok(param, " ");
|
|
int EffectDID = 0, Length, count = 0;
|
|
float scale = 0.0f, speedup = 0.0f;
|
|
short bitmask = 0x07;
|
|
if (cmd)
|
|
{
|
|
EffectDID = atoi(cmd);
|
|
cmd = strtok(NULL, " ");
|
|
count++;
|
|
}
|
|
if (cmd)
|
|
{
|
|
Length = atoi(cmd);
|
|
cmd = strtok(NULL, " ");
|
|
if (cmd)
|
|
{
|
|
scale = atof(cmd);
|
|
bitmask += 0x40;
|
|
cmd = strtok(NULL, " ");
|
|
if (cmd)
|
|
{
|
|
speedup = atof(cmd);
|
|
bitmask += 0x100;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Length = 4000;
|
|
}
|
|
|
|
if (count == 1)
|
|
{
|
|
ObjectToObjectEffect OBTOBE;
|
|
memset(&OBTOBE, 0, sizeof(ObjectToObjectEffect));
|
|
|
|
OBTOBE.Bitmask = bitmask;
|
|
OBTOBE.GameID = chat->GameID;
|
|
OBTOBE.TargetID = m_Player->ShipIndex()->GetTargetGameID();
|
|
OBTOBE.EffectDescID = EffectDID;// 0x00BF;
|
|
OBTOBE.Message = 0;
|
|
OBTOBE.EffectID = m_SectorMgr->GetSectorNextObjID();
|
|
OBTOBE.Duration = Length;
|
|
OBTOBE.TimeStamp = GetNet7TickCount();
|
|
OBTOBE.Scale = scale;
|
|
OBTOBE.Speedup = speedup;
|
|
|
|
m_Player->SendObjectToObjectEffectToRangeList(&OBTOBE);
|
|
m_Player->SendVaMessage("Send Effect %d Disc: %d to Object", OBTOBE.EffectID, EffectDID);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("/effecto <effect_desc_id> <length>");
|
|
}
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("effects", pch, param, msg_sent))
|
|
{
|
|
int EffectID = atoi(strtok(param, " "));
|
|
|
|
SendResponse(ENB_OPCODE_000F_REMOVE_EFFECT, (unsigned char *)&EffectID, sizeof(int));
|
|
|
|
m_Player->SendVaMessage("Stopping Effect %d", EffectID);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'f':
|
|
if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
if (strcmp(pch, "flushinv") == 0)
|
|
{
|
|
// Flush invtory clean!
|
|
for(int Slot=0;Slot<m_Player->ShipIndex()->Inventory.GetCargoSpace();Slot++)
|
|
{
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[Slot].Empty();
|
|
}
|
|
|
|
m_Player->SendAuxShip();
|
|
m_Player->SendVaMessage("Your inventory is now flushed!");
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
if (strcmp(pch,"fetch") == 0) //no args
|
|
{
|
|
success = HandleFetchRequest();
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("find", pch, param, msg_sent))
|
|
{
|
|
Player * target = m_ServerMgr.m_PlayerMgr.GetPlayer(param);
|
|
if (target)
|
|
{
|
|
m_Player->SendVaMessage("Player found! Name: `%s` GameID: %x Account: `%s`",target->Name(), target->GameID(),target->AccountUsername());
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Player `%s` not found!", param);
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (strcmp(pch, "face") == 0)
|
|
{
|
|
success = HandleFaceRequest(m_Player->ShipIndex()->GetTargetGameID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "fgps") == 0)
|
|
{
|
|
ProcessConfirmedActionOffer();
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'g':
|
|
if (strcmp(pch, "goto") == 0)
|
|
{
|
|
success = HandleGotoRequest();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "groupc") == 0)
|
|
{
|
|
m_Player->SendVaMessage("Group Count = %d", m_ServerMgr.m_PlayerMgr.GetMemberCount(m_Player->GroupID()));
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "groupid") == 0)
|
|
{
|
|
m_Player->SendVaMessage("Group ID = %d", m_Player->GroupID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "gameid") == 0)
|
|
{
|
|
m_Player->SendVaMessage("Game ID = %x", m_AvatarID);
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
if (strcmp(pch, "hijack") == 0 && m_Player->ShipIndex()->GetTargetGameID() > 0)
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
success = HandleObjectHijack();
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("You do not have hijack permission.\n" );
|
|
}
|
|
}
|
|
if (strcmp(pch, "heading") == 0)
|
|
{
|
|
float *heading = m_Player->Heading();
|
|
m_Player->SendVaMessage("Heading: %.5f %.5f %.5f", heading[0], heading[1], heading[2]);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (MatchOptWithParam("ht", pch, param, msg_sent))
|
|
{
|
|
int head = atoi(strtok(param, " "));
|
|
int body = atoi(strtok(NULL, " "));
|
|
int gender = atoi(strtok(NULL, " "));
|
|
m_Player->SendVaMessage("Current Head: %d Body: %d G: %d", m_Player->Database()->avatar.head_type, m_Player->Database()->avatar.body_type,
|
|
m_Player->Database()->avatar.gender);
|
|
|
|
m_Player->Database()->avatar.head_type = head;
|
|
m_Player->Database()->avatar.body_type = body;
|
|
m_Player->Database()->avatar.gender = gender;
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
if (MatchOptWithParam("invite", pch, param, msg_sent))
|
|
{
|
|
long GameID = m_ServerMgr.m_PlayerMgr.GetGameIDFromName(param);
|
|
if (GameID == -1)
|
|
{
|
|
m_Player->SendVaMessage("Could not find player %s",param);
|
|
return;
|
|
}
|
|
|
|
if (GameID == m_AvatarID)
|
|
{
|
|
if (!(m_Player->AdminLevel() >= 50)) // GM to Admin
|
|
{
|
|
m_Player->SendVaMessage("Cannot group with yourself!");
|
|
return;
|
|
}
|
|
}
|
|
m_ServerMgr.m_PlayerMgr.GroupInvite(m_Player->GroupID(),m_AvatarID, GameID);
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'k':
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
if (MatchOptWithParam("kick", pch, param, msg_sent))
|
|
{
|
|
success = HandleKick(param);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
case 'l':
|
|
if (strcmp(pch, "leavegroup") == 0)
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.LeaveGroup(m_Player->GroupID(),m_AvatarID);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("level", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
|
|
if (atoi(param) < 0 || atoi(param) > 50)
|
|
{
|
|
m_Player->SendVaMessage("0 <= Level <= 50");
|
|
return;
|
|
}
|
|
|
|
m_Player->PlayerIndex()->RPGInfo.SetCombatLevel(atoi(param));
|
|
m_Player->PlayerIndex()->RPGInfo.SetTradeLevel(atoi(param));
|
|
m_Player->PlayerIndex()->RPGInfo.SetExploreLevel(atoi(param));
|
|
m_Player->PlayerIndex()->RPGInfo.SetSkillPoints(atoi(param) * 10);
|
|
m_Player->LevelUpForSkills();
|
|
m_Player->UpdateSkills();
|
|
m_Player->SendAuxPlayer();
|
|
|
|
m_Player->SendVaMessage("Combat, Explore and Trade LVLs set to %d",atoi(param));
|
|
m_Player->SendVaMessage("Additionally, you now have %d skillpoints",atoi(param) * 10);
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("/level not available");
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'm':
|
|
if (MatchOptWithParam("move", pch, param, msg_sent))
|
|
{
|
|
success = HandleMoveRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
if (strcmp(pch, "ori") == 0)
|
|
{
|
|
float *ori = m_Player->Orientation();
|
|
m_Player->SendVaMessage("Orientation: %.5f %.5f %.5f %.5f", ori[0], ori[1], ori[2], ori[3]);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("orientation", pch, param, msg_sent))
|
|
{
|
|
success = HandleOrientationRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("oeuler", pch, param, msg_sent))
|
|
{
|
|
success = HandleEulerOrientationRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("openif", pch, param, msg_sent))
|
|
{
|
|
char *a = strtok(param, ",");
|
|
char *b = strtok(NULL, ",");
|
|
if (b)
|
|
{
|
|
OpenInterface(atoi(a), atoi(b));
|
|
m_Player->SendVaMessage("OpenInterface (%d,%d):", atoi(a), atoi(b));
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
/*else if (MatchOptWithParam("ore", pch, param, msg_sent))
|
|
{
|
|
char *ch0 = strtok(param, ",");
|
|
int base_energy = 0;
|
|
char *ch = strtok(NULL, ",");
|
|
char *ch2 = strtok(NULL, ",");
|
|
float base_time = 0.0f;
|
|
float base_speed = 0.0f;
|
|
|
|
if (ch0 != 0)
|
|
{
|
|
base_energy = atoi(ch0);
|
|
}
|
|
|
|
if (ch != 0)
|
|
{
|
|
base_time = (float)atof(ch);
|
|
}
|
|
|
|
if (ch2 != 0)
|
|
{
|
|
base_speed = (float)atof(ch2);
|
|
}
|
|
|
|
if (base_energy < 1 || base_time == 0 || base_speed == 0)
|
|
{
|
|
m_Player->SendVaMessage("/ore base ore energy,base ore time,base tractor speed");
|
|
m_Player->SendVaMessage("Base Ore Energy: %d", m_BaseOreEnergy);
|
|
m_Player->SendVaMessage("Base Ore Time: %.2f", m_BaseOreTime);
|
|
m_Player->SendVaMessage("Tractor Speed base: %.2f", m_BaseOreTracSpeed);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("New base ore energy: %d", base_energy);
|
|
m_Player->SendVaMessage("New base ore time: %.2f", base_time);
|
|
m_Player->SendVaMessage("New tractor speed base: %.2f", base_speed);
|
|
|
|
m_BaseOreEnergy = base_energy;
|
|
m_BaseOreTime = base_time;
|
|
m_BaseOreTracSpeed = base_speed;
|
|
}
|
|
msg_sent = true;
|
|
success = true;
|
|
}*/
|
|
break;
|
|
|
|
case 'p':
|
|
if (strcmp(pch, "position") == 0)
|
|
{
|
|
m_Player->SendVaMessage("ObjectID = 0x%08x",m_Player->ShipIndex()->GetTargetGameID());
|
|
if (m_Player->ShipIndex()->GetTargetGameID() != -1)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj) m_Player->SendVaMessage("%s @ %.2f %.2f %.2f", obj->Name(), obj->PosX(), obj->PosY(), obj->PosZ());
|
|
}
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
if (strcmp(pch, "reffect") == 0)
|
|
{
|
|
//m_SectorMgr->m_EffectManager.RemoveEffectsByPlayer(m_AvatarID);
|
|
m_Player->SendVaMessage("Removed all effects on you!");
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (strcmp(pch, "rs") == 0)
|
|
{
|
|
success = HandleRenderStateRequest();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "release") == 0)
|
|
{
|
|
//release hijack
|
|
HandleReleaseHijack();
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (MatchOptWithParam("rsi", pch, param, msg_sent))
|
|
{
|
|
success = HandleRenderStateInitRequest(param);
|
|
}
|
|
else if (MatchOptWithParam("rsa", pch, param, msg_sent))
|
|
{
|
|
success = HandleRenderStateActivateRequest(param);
|
|
}
|
|
else if (MatchOptWithParam("rsn", pch, param, msg_sent))
|
|
{
|
|
success = HandleRenderStateActivateNextRequest(param);
|
|
}
|
|
else if (strcmp(pch, "rsd") == 0)
|
|
{
|
|
success = HandleRenderStateDeactivate();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "range") == 0)
|
|
{
|
|
success = HandleRangeRequest();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "restoreinv") == 0)
|
|
{
|
|
// Flush invtory clean!
|
|
for(int Slot=0;Slot<m_Player->ShipIndex()->Inventory.GetCargoSpace();Slot++)
|
|
{
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[Slot].Empty();
|
|
}
|
|
|
|
m_Player->SendVaMessage("Cargo slots = %d", m_Player->ShipIndex()->Inventory.GetCargoSpace());
|
|
|
|
if (m_Player->ShipIndex()->Inventory.GetCargoSpace() < 20)
|
|
{
|
|
m_Player->ShipIndex()->Inventory.SetCargoSpace(20);
|
|
for(int i=0;i<m_Player->ShipIndex()->Inventory.GetCargoSpace();i++)
|
|
{
|
|
m_Player->ShipIndex()->Inventory.CargoInv.Item[i].Empty();
|
|
}
|
|
m_Player->SendVaMessage("Restored cargo slots = %d", m_Player->ShipIndex()->Inventory.GetCargoSpace());
|
|
}
|
|
|
|
m_Player->SendAuxShip();
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
/*
|
|
else if (strcmp(pch, "refreshmissionlist") == 0)
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
LogMessage("Refreshing mission list\n");
|
|
m_ServerMgr.m_Missions.Initialize();
|
|
success = true;
|
|
}
|
|
}
|
|
*/
|
|
else if (strcmp(pch, "resetmaster") == 0)
|
|
{
|
|
success = HandleResetMaster();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "resetmounts") == 0)
|
|
{
|
|
m_Player->ResetWeaponMounts();
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 's' :
|
|
if (MatchOptWithParam("scale", pch, param, msg_sent))
|
|
{
|
|
success = HandleScaleRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("skillpoints", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
m_Player->PlayerIndex()->RPGInfo.SetSkillPoints(atoi(param));
|
|
m_Player->LevelUpForSkills();
|
|
m_Player->UpdateSkills();
|
|
m_Player->SendAuxPlayer();
|
|
m_Player->SendVaMessage("You now have %d skillpoints", atoi(param));
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("scan", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
long scan_range = atoi(param);
|
|
if (scan_range > 1000)
|
|
{
|
|
//m_Player->ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
m_Player->m_Stats.ResetStat(STAT_SCAN_RANGE);
|
|
m_Player->m_Stats.SetStat(STAT_BASE_VALUE, STAT_SCAN_RANGE, scan_range);
|
|
m_Player->ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
m_Player->SendVaMessage("Scan range set to %d", scan_range);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Set Scan Range: /scan <1000..>", scan_range);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
|
|
if (strcmp(pch, "shutdown") == 0)
|
|
{
|
|
LogMessage(">>>> SHUTDOWN issued by %s [%s]\n", m_Player->Name(), m_Player->AccountUsername());
|
|
m_ServerMgr.m_PlayerMgr.GlobalAdminMessage("Server shutdown in 30 seconds!");
|
|
_sleep(15000);
|
|
m_ServerMgr.m_PlayerMgr.GlobalAdminMessage("Server shutdown in 15 seconds!");
|
|
_sleep(5000);
|
|
m_ServerMgr.m_PlayerMgr.GlobalAdminMessage("Server shutdown in 10 seconds!");
|
|
_sleep(5000);
|
|
m_ServerMgr.m_PlayerMgr.GlobalAdminMessage("Server shutdown in 5 seconds!");
|
|
_sleep(5000);
|
|
m_ServerMgr.m_PlayerMgr.GlobalAdminMessage("Server shutting down!");
|
|
_sleep(5000);
|
|
|
|
g_ServerShutdown = true;
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "sendp") == 0)
|
|
{
|
|
success = true;
|
|
msg_sent = true;
|
|
m_ServerMgr.m_PlayerMgr.SendPlayerWithoutConnection(m_AvatarID);
|
|
}
|
|
else if (strcmp(pch, "strings") == 0)
|
|
{
|
|
char buffer[256];
|
|
g_StringMgr->Statistics(buffer);
|
|
m_Player->SendVaMessage(buffer);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// /test command (do not remove)
|
|
case 't':
|
|
if (strcmp(pch, "test") == 0)
|
|
//if (MatchOptWithParam("test", pch, param, msg_sent))
|
|
{
|
|
m_Player->SendVaMessage("Test Successful!");
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (strcmpi(pch, "talktree") == 0)
|
|
{
|
|
char string[] =
|
|
"That was one heck of an explotion! Are you allright over there?\0"
|
|
"\0\3"
|
|
"\0\0\0\0"
|
|
"I need a tow\0"
|
|
"\1\0\0\0"
|
|
"Toggle distress beacon\0"
|
|
"\2\0\0\0"
|
|
"I'm OK\0";
|
|
|
|
SendResponse(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
}
|
|
if (MatchOptWithParam("testmsg", pch, param, msg_sent))
|
|
{
|
|
long time_delay = atoi(param);
|
|
m_SectorMgr->AddTimedCall(m_Player, B_TEST_MESSAGE, time_delay, 0, time_delay);
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("trade", pch, param, msg_sent))
|
|
{
|
|
// Trade requires that both players recieved a create packet for eachother's ships
|
|
Player * targetp = m_ServerMgr.m_PlayerMgr.GetPlayer(param);
|
|
|
|
if (!targetp)
|
|
{
|
|
m_Player->SendVaMessage("Could not find player %s",param);
|
|
return;
|
|
}
|
|
|
|
if (targetp->GameID() == m_AvatarID)
|
|
{
|
|
if (!(m_Player->AdminLevel() >= 50)) // GM to Admin
|
|
{
|
|
|
|
m_Player->SendVaMessage("Cannot trade with yourself!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (targetp->Connection()->m_TradeID != -1)
|
|
{
|
|
m_Player->SendVaMessage("Target is already trading");
|
|
return;
|
|
}
|
|
|
|
LogDebug("Clearing trade for players `%s` and `%s`\n",m_Player->Name(),targetp->Name());
|
|
|
|
for(int x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
m_Player->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
m_Player->SendAuxShip(targetp);
|
|
targetp->SendAuxShip(m_Player);
|
|
|
|
TradeAction(targetp->GameID(),0); // Opens a trade window
|
|
targetp->Connection()->TradeAction(m_AvatarID, 0); // Open trade window for other player
|
|
m_TradeID = targetp->GameID(); // Set player tradeing with
|
|
m_TradeConferm = 0;
|
|
targetp->Connection()->m_TradeID = m_AvatarID;
|
|
targetp->Connection()->m_TradeConferm = 0;
|
|
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'u' :
|
|
if (MatchOptWithParam("uitrigger", pch, param, msg_sent))
|
|
{
|
|
char *a = strtok(param, ",");
|
|
char *b = strtok(NULL, ",");
|
|
if (b)
|
|
{
|
|
int Index = 0;
|
|
unsigned char Data[75];
|
|
|
|
*((long*) &Data[Index]) = atoi(a);
|
|
Index+=4;
|
|
*((long*) &Data[Index]) = atoi(b);
|
|
Index+=4;
|
|
SendResponse(ENB_OPCODE_0065_UI_TRIGGER, (unsigned char *) &Data, Index);
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("upgrade", pch, param, msg_sent))
|
|
{
|
|
if (m_Player->AdminLevel() >= 30) //Beta +
|
|
{
|
|
long upgrade = atoi(param);
|
|
m_Player->ShipUpgrade(upgrade);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'v':
|
|
if (MatchOptWithParam("verb", pch, param, msg_sent))
|
|
{
|
|
HandleSendVerbRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
case 'w':
|
|
if (strcmp(pch, "who") == 0)
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.ListPlayersAndLocations(m_Player);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (MatchOptWithParam("warp", pch, param, msg_sent))
|
|
{
|
|
int limit = 10000;
|
|
|
|
if (atoi(param) > limit || atoi(param) < 1000)
|
|
{
|
|
m_Player->SendVaMessage("Warp limits are between 1000 and %d!", limit);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Setting warp to %d",atoi(param));
|
|
m_Player->ShipIndex()->CurrentStats.SetWarpSpeed(atoi(param));
|
|
m_Player->SendAuxShip();
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (m_Player->AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
if (MatchOptWithParam("wormhole", pch, param, msg_sent))
|
|
{
|
|
success = HandleWormholeRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
if (strcmp(pch, "warpreset") == 0)
|
|
{
|
|
m_Player->SetWarp();
|
|
m_Player->TerminateWarp();
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!success && !msg_sent)
|
|
{
|
|
m_Player->SendVaMessage("Illegal slash command: %s", pch);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Connection::HandleLogoffRequest()
|
|
{
|
|
//LogoffRequest * request = (LogoffRequest *) m_RecvBuffer;
|
|
LogMessage("Received LogoffRequest for player %s\n",m_Player->Name());
|
|
|
|
//remove player from the group
|
|
m_ServerMgr.m_PlayerMgr.LeaveGroup(m_Player->GroupID(),m_AvatarID);
|
|
|
|
SendLogoffConfirmation();
|
|
|
|
m_SectorMgr->RemovePlayerFromSectorList(m_Player);
|
|
|
|
//now kill the player node
|
|
m_ServerMgr.m_PlayerMgr.UnallocatePlayer(m_Player);
|
|
}
|
|
|
|
void Connection::HandleCTARequest()
|
|
{
|
|
CTARequest * myCTARequest = (CTARequest *) m_RecvBuffer;
|
|
|
|
LogMessage("CTA Request:\n");
|
|
DumpBuffer(m_RecvBuffer, sizeof(CTARequest));
|
|
|
|
m_ServerMgr.m_PlayerMgr.GroupAction(myCTARequest->SourceID, myCTARequest->TargetID, myCTARequest->Action);
|
|
|
|
//capture_3 packet# 21495
|
|
unsigned char CTAResponse[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x00, //GameID
|
|
0x0F, 0x00, 0x00, 0x00, //Unknown
|
|
0x01 //Char
|
|
};
|
|
|
|
*((long*) &CTAResponse[0]) = myCTARequest->SourceID;
|
|
|
|
SendResponse(ENB_OPCODE_00BD_CTA_RESPONSE, (unsigned char *) &CTAResponse, sizeof(CTAResponse));
|
|
}
|
|
|
|
void Connection::SendLogoffConfirmation()
|
|
{
|
|
LogMessage("Sending LogoffConfirmation packet\n");
|
|
SendResponse(ENB_OPCODE_00BA_LOGOFF_CONFIRMATION);
|
|
}
|
|
|
|
void Connection::HandleStarbaseAvatarChange()
|
|
{
|
|
StarbaseAvatarChange *pkt = (StarbaseAvatarChange *) m_RecvBuffer;
|
|
//LogMessage("Received StarbaseAvatarChange packet\n");
|
|
/*LogMessage("{AvatarID=%d RoomType=%d Orient=%f Position=(%f,%f,%f) ActionFlag=%d}\n",
|
|
pkt->AvatarID, pkt->RoomType, pkt->Orient,
|
|
pkt->Position[0], pkt->Position[1], pkt->Position[2],
|
|
pkt->ActionFlag);*/
|
|
|
|
m_Player->HandleStarbaseAvatarChange(m_SectorID, pkt);
|
|
}
|
|
|
|
void Connection::HandleStarbaseRoomChange()
|
|
{
|
|
StarbaseRoomChange *pkt = (StarbaseRoomChange *) m_RecvBuffer;
|
|
//LogMessage("Received StarbaseRoomChange packet\n");
|
|
m_Player->HandleStarbaseRoomChange(m_SectorID, pkt);
|
|
}
|
|
|
|
void Connection::SendTalkTreeAction(long action)
|
|
{
|
|
//LogMessage("Sending TalkTreeAction packet\n");
|
|
SendResponse(ENB_OPCODE_0056_TALK_TREE_ACTION, (unsigned char *) &action, sizeof(long));
|
|
}
|
|
|
|
bool Connection::HandleRangeRequest()
|
|
{
|
|
bool success = false;
|
|
|
|
if (m_Player->ShipIndex()->GetTargetGameID() > 0)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
m_Player->SendVaMessage("Range to object = %f", obj->RangeFrom(m_Player->Position(), true)); //report absolute range
|
|
success = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleWormholeRequest(char *sector)
|
|
{
|
|
bool success = false;
|
|
bool illegal_dest = false;
|
|
|
|
if (m_Player->PlayerIndex()->GetSectorNum() > 9999)
|
|
{
|
|
//m_Player->SendVaMessage("Unable to wormhole out of starbase, disembark first.");
|
|
SendStarbaseSet(1, 0);
|
|
SetManufactureID(0);
|
|
}
|
|
|
|
if (m_SectorMgr)
|
|
{
|
|
m_Player->TerminateWarp();
|
|
long sector_id = atoi(sector);
|
|
/*
|
|
if (sector_id > 9999)
|
|
{
|
|
sector_id /= 10;
|
|
}
|
|
*/
|
|
|
|
switch (sector_id)
|
|
{
|
|
case 1493:
|
|
case 1930:
|
|
case 2290:
|
|
case 2295:
|
|
case 3595:
|
|
case 4195:
|
|
case 4595:
|
|
case 4095:
|
|
case 4093:
|
|
illegal_dest = true;
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
char *current_sector_name = m_ServerMgr.m_SectorServerMgr.GetSectorName(m_SectorID);
|
|
char *sector_name = m_ServerMgr.m_SectorServerMgr.GetSectorName(sector_id);
|
|
if (sector_name && !illegal_dest)
|
|
{
|
|
m_Player->SendVaMessage("Wormhole from %s to %s\n", current_sector_name, sector_name);
|
|
m_Player->SendVaMessage("Wormhole out of sector %d", m_SectorID);
|
|
|
|
m_Player->RemoveFromAllSectorRangeLists();
|
|
|
|
//Hand off server
|
|
m_SectorMgr->SectorServerHandoff(this, sector_id);
|
|
|
|
//set to new server;
|
|
m_SectorID = sector_id;
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Invalid or Illegal Sector ID %d", sector_id);
|
|
}
|
|
}
|
|
|
|
m_Player->RemoveProspectNodes();
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleKick(char *param)
|
|
{
|
|
char Message[1024];
|
|
|
|
char *name = strtok(param, " ");
|
|
char *reason = 0;
|
|
|
|
if (name)
|
|
reason = strtok(NULL, "");
|
|
else
|
|
return 0;
|
|
|
|
Player * target = m_ServerMgr.m_PlayerMgr.GetPlayer(name);
|
|
|
|
if (!reason)
|
|
{
|
|
reason = new char[50];
|
|
sprintf(reason, "No Reason Given");
|
|
}
|
|
|
|
if (target && target->ConnectionAvailable())
|
|
{
|
|
sprintf(Message, "Player '%s' kicked by '%s': %s", target->Name(), m_Player->Name(), reason);
|
|
LogMessage(" ** Kick: %s\n", Message);
|
|
|
|
target->Connection()->m_Player->SendVaMessage("You have been kicked by %s: %s", m_Player->Name(), reason);
|
|
m_ServerMgr.m_PlayerMgr.GMMessage(Message);
|
|
_sleep(100);
|
|
target->Connection()->ForceLogout();
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Connection::ForceLogout()
|
|
{
|
|
int Count = 0;
|
|
|
|
// Wait 30 seconds for the player to become active, while in space
|
|
while (!m_Player->Active() && m_Player->PlayerIndex()->GetSectorNum() < 10000 && Count < 30)
|
|
{
|
|
_sleep(1000);
|
|
Count++;
|
|
}
|
|
|
|
// Give them 5 seconds to read the kick message!
|
|
_sleep(5000);
|
|
|
|
SendResponse(ENB_OPCODE_0003_LOGOFF, (unsigned char*)&m_AvatarID, sizeof(m_AvatarID));
|
|
_sleep(100);
|
|
|
|
m_ServerMgr.m_PlayerMgr.LeaveGroup(m_Player->GroupID(),m_AvatarID);
|
|
m_SectorMgr->RemovePlayerFromSectorList(m_Player);
|
|
m_ServerMgr.m_PlayerMgr.UnallocatePlayer(m_Player);
|
|
m_TcpThreadRunning = false;
|
|
}
|
|
|
|
bool Connection::HandleMoveRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
float x, y, z;
|
|
char *a = strtok(param, ",");
|
|
char *b = strtok(NULL, ",");
|
|
char *c = strtok(NULL, ",");
|
|
|
|
x = y = z = 0.0f;
|
|
|
|
if (a == NULL)
|
|
{
|
|
m_Player->SendVaMessage("/move: syntax: x,y,z");
|
|
m_Player->SendVaMessage("/move: all parameters float type");
|
|
}
|
|
else
|
|
{
|
|
x = (float)atof(a);
|
|
|
|
if (b != NULL)
|
|
{
|
|
y = (float)atof(b);
|
|
}
|
|
else
|
|
{
|
|
y = m_Player->PosY();
|
|
}
|
|
|
|
if (c != NULL)
|
|
{
|
|
z = (float)atof(c);
|
|
}
|
|
else
|
|
{
|
|
z = m_Player->PosZ();
|
|
}
|
|
}
|
|
|
|
if (!m_Player)
|
|
{
|
|
m_Player->SetPosition(x, y, z);
|
|
|
|
m_Player->SendVaMessage("Setting position to : %d %d %d", x, y, z);
|
|
|
|
//m_ServerMgr.m_PlayerMgr.SendLocation(m_Player, m_Player);
|
|
//CheckTargetUpdate();
|
|
m_Player->UpdateVerbs();
|
|
CheckObjectRanges();
|
|
success = true;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
bool Connection::HandleOrientationRequest(char *orientation)
|
|
{
|
|
bool success = false;
|
|
float o1, o2, o3, o4;
|
|
char *a = strtok(orientation, ",");
|
|
char *b = strtok(NULL, ",");
|
|
char *c = strtok(NULL, ",");
|
|
char *d = strtok(NULL, ",");
|
|
|
|
o1 = o2 = o3 = o4 = 0.0f;
|
|
|
|
if (a == NULL)//allow incomplete args
|
|
{
|
|
m_Player->SendVaMessage("/orientation: syntax: o1,o2,o3,o4");
|
|
m_Player->SendVaMessage("/orientation: all parameters float type");
|
|
}
|
|
else
|
|
{
|
|
o1 = (float)atof(a);
|
|
|
|
if (b != NULL)
|
|
{
|
|
o2 = (float)atof(b);
|
|
}
|
|
if (c != NULL)
|
|
{
|
|
o3 = (float)atof(c);
|
|
}
|
|
if (d != NULL)
|
|
{
|
|
o4 = (float)atof(d);
|
|
}
|
|
|
|
|
|
Object *obj;
|
|
|
|
m_Player->SendVaMessage("Targetting 0x%08x Player = 0x%08x (%08x)",m_Player->ShipIndex()->GetTargetGameID(), m_AvatarID, m_AvatarID);
|
|
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj)
|
|
{
|
|
//New orientation info:
|
|
obj->SetOrientation(o1, o2, o3, o4);
|
|
|
|
m_Player->SendVaMessage("Object name: %s", obj->Name());
|
|
|
|
obj->SendPosition(this);
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleFaceRequest(long Target)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(Target);
|
|
|
|
if (obj)
|
|
{
|
|
m_Player->Face(obj);
|
|
m_Player->SendLocationAndSpeed(true);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleEulerOrientationRequest(char *orientation)
|
|
{
|
|
bool success = false;
|
|
float o1, o2, o3;
|
|
char *a = strtok(orientation, ",");
|
|
char *b = strtok(NULL, ",");
|
|
char *c = strtok(NULL, ",");
|
|
|
|
o1 = o2 = o3 = 0.0f;
|
|
|
|
if (a == NULL)//allow incomplete args
|
|
{
|
|
m_Player->SendVaMessage("/oeuler: syntax: heading,alt,bank");
|
|
m_Player->SendVaMessage("/oeuler: all parameters float type");
|
|
}
|
|
else
|
|
{
|
|
o1 = (float)atof(a);
|
|
|
|
if (b != NULL)
|
|
{
|
|
o2 = (float)atof(b);
|
|
}
|
|
if (c != NULL)
|
|
{
|
|
o3 = (float)atof(c);
|
|
}
|
|
|
|
if (o1 == 180.0f) o1 = o1 + 0.5f;
|
|
if (o2 == 180.0f) o2 = o2 + 0.5f;
|
|
if (o3 == 180.0f) o3 = o3 + 0.5f;
|
|
|
|
o1 = o1 / 180.0f * PI;
|
|
o2 = o2 / 180.0f * PI;
|
|
o3 = o3 / 180.0f * PI;
|
|
|
|
Object *obj;
|
|
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (!obj)
|
|
{
|
|
obj = m_CurrentDecoObj;
|
|
}
|
|
|
|
if (obj)
|
|
{
|
|
//New orientation info:
|
|
obj->SetEulerOrientation(o1,o2,o3);
|
|
|
|
m_Player->SendVaMessage("Object name: %s", obj->Name());
|
|
m_Player->SendVaMessage("Setting Euler orientation to %.2f,%.2f,%.2f",o1*180.0f/PI,o2*180.0f/PI,o3*180.0f/PI);
|
|
float *vector;
|
|
vector = obj->Orientation();
|
|
m_Player->SendVaMessage("Setting Quaternion orientation to %.4f,%.4f,%.4f,%.4f",vector[0],vector[1],vector[2],vector[3]);
|
|
|
|
obj->SendPosition(this);
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleMobCreateRequest(char *param)
|
|
{
|
|
char *pch_parse, *name = 0;
|
|
short level = 0;
|
|
short mob_type = 0;
|
|
short mob_count = 0;
|
|
bool direct_basset = false;
|
|
bool directional = false;
|
|
float velocity = 100.0f;
|
|
float turn = 0.2f;
|
|
float xoffset = 300.0f;
|
|
|
|
//are we trying to create a mob too close to a station?
|
|
/*
|
|
Object *obj = m_Player->NearestNav();
|
|
|
|
if (obj)
|
|
{
|
|
// Allow turrets to be put near stations
|
|
if (obj->ObjectType() == OT_STATION && (obj->RangeFrom(m_Player->Position()) < 5000.0f || mob_type == 14))
|
|
{
|
|
m_Player->SendVaMessage("You're trying to create a MOB too close to a station. Move to at least 5K away.");
|
|
return false;
|
|
}
|
|
}
|
|
*/
|
|
|
|
while (MobData[mob_count].basset != 0)
|
|
{
|
|
mob_count++;
|
|
};
|
|
|
|
pch_parse = strtok(param, " ");
|
|
|
|
if (!pch_parse)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (*pch_parse == 'B')
|
|
{
|
|
//direct basset method
|
|
pch_parse = strtok(NULL, " ");
|
|
direct_basset = true;
|
|
}
|
|
else if (*pch_parse == 'D')
|
|
{
|
|
pch_parse = strtok(NULL, " ");
|
|
directional = true;
|
|
level = 30;
|
|
mob_type = MOB_EnergyPhoenix;
|
|
name = MobData[mob_type].name;
|
|
if (pch_parse)
|
|
{
|
|
xoffset = atof(pch_parse);
|
|
pch_parse = strtok(NULL, " ");
|
|
if (pch_parse)
|
|
{
|
|
velocity = atof(pch_parse);
|
|
pch_parse = strtok(NULL, " ");
|
|
if (pch_parse)
|
|
{
|
|
turn = atof(pch_parse);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pch_parse && directional == false)
|
|
{
|
|
mob_type = (long)atoi(pch_parse);
|
|
pch_parse = strtok(NULL, " ");
|
|
if (pch_parse)
|
|
{
|
|
level = atoi(pch_parse);
|
|
name = strtok(NULL, " ");
|
|
}
|
|
}
|
|
|
|
if ((level > 0 && level < 67) && ( (mob_type > -1 && mob_type < mob_count) || direct_basset == true) )
|
|
{
|
|
MOB *mob = (MOB*)m_ObjectMgr->AddNewObject(OT_MOB); //MOB creation
|
|
|
|
if (!name)
|
|
{
|
|
name = MobData[mob_type].name;
|
|
}
|
|
|
|
if (mob)
|
|
{
|
|
if (direct_basset)
|
|
{
|
|
m_Player->SendVaMessage("Creating %d at level %d (%s)", mob_type, level, name);
|
|
mob->SetMOBType(0);
|
|
mob->SetBasset(mob_type);
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Creating %s at level %d (%s)", MobData[mob_type].name, level, name);
|
|
mob->SetMOBType(mob_type);
|
|
}
|
|
mob->SetName(name);
|
|
mob->SetPosition(m_Player->Position());
|
|
mob->MovePosition(xoffset, 0.0f, -200.0f);
|
|
mob->SetLevel(mob_type == 14? 66 : level);
|
|
mob->SetActive(true);
|
|
mob->SetRespawnTick(0);
|
|
|
|
// For Turretts
|
|
if (mob_type == 14) {
|
|
velocity = 0;
|
|
mob->SetHostileTo(OT_MOB);
|
|
mob->Turn(0);
|
|
} else {
|
|
mob->SetHostileTo(OT_PLAYER);
|
|
mob->Turn(turn);
|
|
}
|
|
mob->SetVelocity(velocity);
|
|
mob->SetDefaultStats(turn, MobData[mob_type].behaviour, velocity, 50);
|
|
mob->SetUpdateRate(50);
|
|
mob->SetBehaviour(MobData[mob_type].behaviour);
|
|
mob->AddBehaviourPosition(m_Player->Position());
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to create MOB at this time.");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Create Mob: /createmob <MOB type>0..%d <level>1..66 <name>", (mob_count - 1));
|
|
mob_count = 0;
|
|
while (MobData[mob_count].basset != 0)
|
|
{
|
|
m_Player->SendVaMessage(" type %d: %s", mob_count, MobData[mob_count].name);
|
|
mob_count++;
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Connection::HandleObjCreateRequest(char *param)
|
|
{
|
|
char *pch_level;
|
|
short level = 0;
|
|
pch_level = strchr(param, ' ');
|
|
|
|
if (strcmp(param, "ON") == 0)
|
|
{
|
|
m_Player->SendVaMessage("Resource Creation ACTIVATED");
|
|
m_Player->SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
m_ServerMgr.m_AllowCreate = true;
|
|
return true;
|
|
}
|
|
else if (strcmp(param, "XML") == 0)
|
|
{
|
|
m_Player->SendVaMessage("XML output on");
|
|
m_ServerMgr.m_DumpXML = true;
|
|
return true;
|
|
}
|
|
else if (strncmp(param, "F", 1) == 0)
|
|
{
|
|
char *pch_lev = 0;
|
|
char *pch_number = 0;
|
|
char *pch_radius = 0;
|
|
int type = 0;
|
|
int number = 0;
|
|
int radius = 0;
|
|
|
|
if (pch_level) pch_lev = strchr(pch_level + 1, ' ');
|
|
if (pch_lev) pch_number = strchr(pch_lev + 1, ' ');
|
|
if (pch_number) pch_radius = strchr(pch_number + 1, ' ');
|
|
|
|
if (pch_lev && pch_level && pch_number && pch_radius)
|
|
{
|
|
type = atoi(pch_level + 1);
|
|
level = atoi(pch_lev + 1);
|
|
number = atoi(pch_number + 1);
|
|
radius = atoi(pch_radius + 1);
|
|
}
|
|
|
|
if (radius < 3000.0f || number < 1 || level > 8 || type > 9 || level < 1 || type < 1)
|
|
{
|
|
m_Player->SendVaMessage("Create Asteroid field: /create F <type>1..9 <level>1..8 <count>1.. <radius>1.. ");
|
|
return false;
|
|
}
|
|
else if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
Object *obj = m_ObjectMgr->AddNewObject(OT_FIELD); //complete creation of field
|
|
obj->SetFieldRadius((float)radius);
|
|
obj->SetLevel(level);
|
|
obj->SetFieldCount(number);
|
|
obj->SetFieldType(type);
|
|
obj->SetPosition(m_Player->Position());
|
|
obj->PopulateField(); // issue field
|
|
m_Player->SendVaMessage("Asteroid field created. Level:%d Count:%d Radius:%d", level, number, radius);
|
|
m_ObjectMgr->DisplayDynamicObjects(m_Player, true); //update display for all roids.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("%s, you can't create an asteroid field ... yet.", m_Player->Name());
|
|
return false;
|
|
}
|
|
}
|
|
else if (strncmp(param, "M", 1) == 0)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
//p->Connection()->m_SectorMgr->GetMobPosition(mob, &position[0]);
|
|
//mob->position_info.Position
|
|
//m_SectorMgr->GetMobPosition(obj, &position[0]);
|
|
|
|
|
|
|
|
/*position[0] = obj->position_info.Position[0];
|
|
position[1] = obj->position_info.Position[1];
|
|
position[2] = obj->position_info.Position[2];*/
|
|
//m_SectorMgr->AddNewObject(this, 9, 7, &position[0]);
|
|
}
|
|
}
|
|
else if (m_ServerMgr.m_AllowCreate == false)
|
|
{
|
|
m_Player->SendVaMessage("Create Resource: Unable to create resource");
|
|
return false;
|
|
}
|
|
|
|
if (!pch_level)
|
|
{
|
|
m_Player->SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
return false;
|
|
}
|
|
|
|
short object_type = (long)atoi(param);
|
|
|
|
level = atoi(pch_level + 1);
|
|
|
|
if ((level > 0 && level < 10) && (object_type > -1 && object_type < 13))
|
|
{
|
|
Object *obj = m_ObjectMgr->AddNewObject(OT_RESOURCE);
|
|
obj->SetTypeAndName(object_type);
|
|
obj->SetLevel(level);
|
|
obj->SetPosition(m_Player->Position());
|
|
obj->ResetResource(); //populate with items
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Connection::ChangeSectorID(long SectorID)
|
|
{
|
|
m_ServerMgr.m_PlayerMgr.SetSector(m_Player, SectorID);
|
|
}
|
|
|
|
bool Connection::HandleFetchRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
obj->SetPosition(m_Player->Position());
|
|
m_Player->SendVaMessage("Object name: %s", obj->Name());
|
|
obj->SendPosition(this); //TODO: send new position to everyone
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleObjectHijack()
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj)
|
|
{
|
|
//try a different approach with this.
|
|
//lets try just locking the position of the hijacked object onto the player's ship
|
|
//and not showing the ship to anyone else
|
|
m_Player->SendVaMessage("You have been successfully assigned to control '%s'.", obj->Name());
|
|
LogMessage("HIJACK occurred. Account name '%s'.\n", m_Player->AccountUsername());
|
|
|
|
m_Player->HijackObject(obj);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to hijack object with GameID %d.\n", m_Player->ShipIndex()->GetTargetGameID());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Connection::HandleReleaseHijack()
|
|
{
|
|
if (m_Player->Hijackee())
|
|
{
|
|
m_Player->SendVaMessage("You have been unassigned from control of '%s'.", m_Player->Hijackee()->Name());
|
|
m_Player->Hijackee()->SetPlayerHijack(0);
|
|
m_Player->SetHijackee(0);
|
|
}
|
|
}
|
|
|
|
bool Connection::HandleGotoRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
bool admin = false;
|
|
|
|
//only allow admins to jump to resources
|
|
if (m_Player->AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
admin = true;
|
|
}
|
|
|
|
if (admin == false)
|
|
{
|
|
m_Player->SendVaMessage("/goto has been disabled");
|
|
return (false);
|
|
}
|
|
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
m_Player->SetPosition(obj->Position());
|
|
m_Player->SendLocationAndSpeed(true);
|
|
m_Player->UpdateVerbs();
|
|
CheckObjectRanges();
|
|
m_Player->CheckNavs();
|
|
success = true;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
void Connection::GateSequenceEnd()
|
|
{
|
|
m_StargateID = 0;
|
|
m_SectorMgr->GateJump(this);
|
|
}
|
|
|
|
//First sequence for Stargate open
|
|
void Connection::OpenStargate_1()
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj && obj->ObjectType() == OT_STARGATE)
|
|
{
|
|
SendActivateRenderState(m_Player->ShipIndex()->GetTargetGameID(), 2);
|
|
obj->SetRenderState(2);
|
|
}
|
|
}
|
|
|
|
void Connection::OpenStargate_2(long object_id)
|
|
{
|
|
SendActivateNextRenderState(object_id, 1);
|
|
}
|
|
|
|
void Connection::CloseStargate(long object_id)
|
|
{
|
|
SendActivateNextRenderState(object_id, 3);
|
|
}
|
|
|
|
bool Connection::HandleRenderStateRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj)
|
|
{
|
|
m_Player->SendVaMessage("Object '%s'", obj->Name());
|
|
m_Player->SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
//m_Player->SendVaMessage("Allowable Render State = 0x%X", obj->allowable_render_states);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleScaleRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
if (m_SectorMgr && (m_Player->ShipIndex()->GetTargetGameID() > 0 || m_CurrentDecoObj))
|
|
{
|
|
float scale = (float) atof(param);
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (!obj) obj = m_CurrentDecoObj;
|
|
|
|
if (obj)
|
|
{
|
|
if (scale == 0.0)
|
|
{
|
|
// Display current scale
|
|
m_Player->SendVaMessage("Scale of %s is currently %.2f", obj->Name(), obj->Scale());
|
|
}
|
|
else
|
|
{
|
|
// Set new scale
|
|
m_Player->SendVaMessage("Changing scale from %g to %g", obj->Scale(), scale);
|
|
obj->SetScale(scale);
|
|
long target_id = obj->GameID();
|
|
// Remove the Object
|
|
obj->Remove();
|
|
// Recreate the Object
|
|
obj->SendObject(m_Player);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::SendLoungeNPC(long StationID)
|
|
{
|
|
#ifdef USE_MYSQL_STATIONS
|
|
struct StationLounge LoungeData;
|
|
unsigned char bufferd[10000];
|
|
unsigned char *buffer = bufferd;
|
|
int Size, x;
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
memset(&LoungeData, 0, sizeof(LoungeData));
|
|
|
|
StationTemplate * Stn = m_ServerMgr.m_StationList;
|
|
|
|
while(Stn && Stn->StationID != StationID)
|
|
{
|
|
Stn = Stn->next;
|
|
}
|
|
|
|
if (!Stn) // Station not found?
|
|
return false;
|
|
|
|
LoungeData.Station.StationType = Stn->Type;
|
|
LoungeData.Station.RoomNumber = Stn->NumRooms;
|
|
LoungeData.NumTerms = Stn->NumTerms;
|
|
LoungeData.NumNPCs = Stn->NumNPCs;
|
|
|
|
NPCTemplate * NPCs = Stn->NPCs;
|
|
for(x=0;x<Stn->NumNPCs;x++)
|
|
{
|
|
LoungeData.NPC[x].BoothType = NPCs->Booth;
|
|
LoungeData.NPC[x].Location = NPCs->Location;
|
|
LoungeData.NPC[x].NPCID = NPCs->StarbaseID;
|
|
LoungeData.NPC[x].RoomNumber = NPCs->Room;
|
|
memcpy(&LoungeData.NPC[x].Avatar,&NPCs->Avatar,sizeof(AvatarData));
|
|
NPCs = NPCs->next;
|
|
}
|
|
|
|
RoomTemplate * Rooms = Stn->Rooms;
|
|
for(x=0;x<Stn->NumRooms;x++)
|
|
{
|
|
LoungeData.Rooms[x].RoomNumber = Rooms->Index;
|
|
LoungeData.Rooms[x].RoomStyle = Rooms->Style;
|
|
LoungeData.Rooms[x].FogFar = Rooms->FogFar;
|
|
LoungeData.Rooms[x].FogNear = Rooms->FogNear;
|
|
LoungeData.Rooms[x].FogRed = Rooms->FogRed;
|
|
LoungeData.Rooms[x].FogGreen = Rooms->FogGreen;
|
|
LoungeData.Rooms[x].FogBlue = Rooms->FogBlue;
|
|
|
|
Rooms = Rooms->next;
|
|
}
|
|
|
|
TermTemplate * Terms = Stn->Terms;
|
|
for(x=0;x<Stn->NumTerms;x++)
|
|
{
|
|
LoungeData.Terms[x].TermType = Terms->Type;
|
|
LoungeData.Terms[x].Location = Terms->Location;
|
|
LoungeData.Terms[x].RoomNumber = Terms->Room;
|
|
Terms = Terms->next;
|
|
}
|
|
|
|
memcpy(buffer,&LoungeData.Station,sizeof(LoungeData.Station));
|
|
buffer+=sizeof(LoungeData.Station);
|
|
|
|
for(x=0;x<LoungeData.Station.RoomNumber;x++)
|
|
{
|
|
memcpy(buffer,&LoungeData.Rooms[x],sizeof(LoungeData.Rooms[x]));
|
|
buffer+=sizeof(LoungeData.Rooms[x]);
|
|
}
|
|
|
|
*((int *) buffer) = LoungeData.NumTerms; buffer+=4;
|
|
|
|
for(x=0;x<LoungeData.NumTerms;x++)
|
|
{
|
|
memcpy(buffer,&LoungeData.Terms[x], sizeof(LoungeData.Terms[x]));
|
|
buffer+=sizeof(LoungeData.Terms[x]);
|
|
}
|
|
|
|
*((int *) buffer) = LoungeData.NumNPCs; buffer+=4;
|
|
|
|
for(x=0;x<LoungeData.NumNPCs;x++)
|
|
{
|
|
memcpy(buffer,&LoungeData.NPC[x], sizeof(LoungeData.NPC[x]));
|
|
buffer+=sizeof(LoungeData.NPC[x]);
|
|
}
|
|
|
|
Size = buffer - &bufferd[0];
|
|
|
|
SendResponse(ENB_OPCODE_0052_LOUNGE_NPC, (unsigned char *) bufferd, Size);
|
|
|
|
//LogMessage("Loaded Station from MySQL (%d)\n", m_SectorID);
|
|
|
|
//DumpBuffer(bufferd, Size);
|
|
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
//Not too sure on the data structure of this packet
|
|
bool Connection::HandleRenderStateInitRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
long render_state = atol(param);
|
|
|
|
if (obj != NULL)
|
|
{
|
|
m_Player->SendVaMessage("Object '%s'", obj->Name());
|
|
m_Player->SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
m_Player->SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
m_Player->SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendInitRenderState(m_Player->ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState(render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleRenderStateActivateRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
long render_state = atol(param);
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
m_Player->SendVaMessage("Object '%s'", obj->Name());
|
|
m_Player->SendVaMessage("Activate Render State: 2 = open gate half way");
|
|
m_Player->SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
m_Player->SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
m_Player->SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendActivateRenderState(m_Player->ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState(render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleRenderStateActivateNextRequest(char * param)
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
long render_state = atol(param);
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
m_Player->SendVaMessage("Object '%s'", obj->Name());
|
|
m_Player->SendVaMessage("Activate Next Render State: 1 = Gate opens fully 3 = gate closes");
|
|
m_Player->SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
m_Player->SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
m_Player->SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendActivateNextRenderState(m_Player->ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState(render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Connection::HandleRenderStateDeactivate()
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
obj = m_ObjectMgr->GetObjectFromID(m_Player->ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
m_Player->SendVaMessage("Object '%s'", obj->Name());
|
|
m_Player->SendVaMessage("Deactivate Render State");
|
|
m_Player->SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
m_Player->SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
m_Player->SendVaMessage("New Render State = 0x%X", 0);
|
|
SendDeactivateRenderState(m_Player->ShipIndex()->GetTargetGameID());
|
|
obj->SetRenderState(0); //Not sure if I should be changing this here
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
m_Player->SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
void Connection::HandleStarbaseRequest()
|
|
{
|
|
StarbaseRequest * pkt = (StarbaseRequest *) m_RecvBuffer;
|
|
|
|
LogDebug("Starbase Request - PlayerID: %d Action: %d StarBaseID: %d\n",pkt->PlayerID, pkt->Action, pkt->StarbaseID);
|
|
|
|
char *professions[] =
|
|
{
|
|
" Warriors",
|
|
" Traders",
|
|
"Explorers"
|
|
};
|
|
|
|
char string[] =
|
|
"/happy1 Hello! Hello - step right up, Sir. Explorers are welcome here. How can I help you?\0"
|
|
"\0\2"
|
|
"\0\0\0\0"
|
|
"I would like to trade\0"
|
|
"\1\0\0\0"
|
|
"Nothing today\0";
|
|
|
|
memcpy((string+43),professions[m_Player->Profession()], 9);
|
|
|
|
printf("Received StarbaseRequest packet, PlayerID=%x, StarbaseID=%d, Action=%d\n",
|
|
pkt->PlayerID, pkt->StarbaseID, pkt->Action);
|
|
|
|
m_TradeWindow = false;
|
|
|
|
switch(pkt->Action)
|
|
{
|
|
case 1: // Exiting the station action
|
|
if (pkt->StarbaseID == m_SectorID && m_SectorMgr)
|
|
{
|
|
if (m_TradeID != -1)
|
|
CancelTrade();
|
|
// Launch into space!
|
|
m_SectorMgr->LaunchIntoSpace(this);
|
|
}
|
|
break;
|
|
case 4: // Talk to NPC
|
|
m_StarbaseTargetID = pkt->StarbaseID;
|
|
// Display the standard talk tree unless we have a mission here
|
|
if (m_Player->CheckMissions(0, 1, 0, m_StarbaseTargetID) ||
|
|
m_Player->CheckForNewMissions(0, 1, 0, m_StarbaseTargetID) )
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
SendResponse(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
m_StarbaseTargetID = pkt->StarbaseID;
|
|
}
|
|
break;
|
|
case 6: // Activating Job Terminal
|
|
{
|
|
/*
|
|
PacketBuffer buffer;
|
|
|
|
m_ServerMgr.m_Jobs.GetJobList(this, &buffer);
|
|
SendResponse(ENB_OPCODE_0093_JOB_LIST, buffer.getBuffer(), buffer.size());
|
|
*/
|
|
|
|
break;
|
|
}
|
|
case 7: // Clicking on a job on the job terminal to pull up a job description
|
|
{ /* JobDescription structure
|
|
|
|
0x00, 0x00, 0x00, 0x00, // JobDescriptionID
|
|
0x00, // Is this job still available? (0x00 = no, 0x01 = yes)
|
|
0xXX, ........... 0x00, // Variable length null terminated "Title" string
|
|
0xXX, ........... 0x00, // Variable length null terminated "Description" string
|
|
*/
|
|
|
|
|
|
/*
|
|
PacketBuffer buffer;
|
|
|
|
m_ServerMgr.m_Jobs.GetJobDescription(pkt->StarbaseID, &buffer, &m_ServerMgr.m_TokenParser);
|
|
SendResponse(ENB_OPCODE_0094_JOB_DESCRIPTION, buffer.getBuffer(), buffer.size());
|
|
|
|
_Item myItem;
|
|
memset(&myItem,0,sizeof(_Item));
|
|
|
|
int itemId = m_ServerMgr.m_Jobs.GetItem(pkt->StarbaseID);
|
|
|
|
ItemBase * item = g_ItemBaseMgr->GetItem(itemId);
|
|
|
|
if (item)
|
|
{
|
|
myItem.ItemTemplateID = itemId;
|
|
myItem.Price = item->Cost();
|
|
myItem.Quality = 1.0f;
|
|
myItem.Structure = 1.0f;
|
|
myItem.StackCount = 1;
|
|
|
|
printf("itemID: %d\n", itemId);
|
|
|
|
|
|
ItemBase *myItemBase = g_ItemBaseMgr->GetItem(myItem.ItemTemplateID);
|
|
m_Player->SendItemBase(myItem.ItemTemplateID);
|
|
|
|
m_Player->PlayerIndex()->RewardInv.Item[0].SetData(&myItem);
|
|
m_Player->SendAuxPlayer();
|
|
}
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
case 8: // Accept job?
|
|
LogMessage("Accepting Job\n");
|
|
SendResponse(ENB_OPCODE_0096_JOB_ACCEPT_REPLY);
|
|
// Eventually we'll be able to accept jobs once the system is fixed.
|
|
//m_ServerMgr.m_Missions.givePlayerMission(this, 1);
|
|
break;
|
|
case 9: // ??
|
|
break;
|
|
case 10: // Customize avatar - NOT WORKING YET
|
|
SendResponse(ENB_OPCODE_0083_RECUSTOMIZE_AVATAR_START);
|
|
break;
|
|
case 11: // Customize starship - NOT WORKING YET
|
|
SendResponse(ENB_OPCODE_0081_RECUSTOMIZE_SHIP_START);
|
|
}
|
|
}
|
|
|
|
|
|
void Connection::SetManufactureID(long mfg_id)
|
|
{
|
|
//LogMessage("Sending SetManufactureID packet\n");
|
|
SendResponse(ENB_OPCODE_007F_MANUFACTURE_SET_MANUFACTURE_ID, (unsigned char *) &mfg_id, sizeof(mfg_id));
|
|
}
|
|
|
|
/*
|
|
1C 00 "Friendship 7 Recreation Port"
|
|
00 00 ""
|
|
05 00 "Glenn"
|
|
0A 00 "Beta Hydri"
|
|
|
|
20 00 "Glenn Sector (Beta Hydri System) from sector
|
|
0A 00 "Beta Hydri" from system
|
|
0E 00 "Swooping Eagle" to sector
|
|
06 00 "Sirius" to system
|
|
|
|
*/
|
|
|
|
//TODO: Recode using new packet methods
|
|
void Connection::SendServerHandoff(long from_sector_id, long to_sector_id, char *from_sector, char *from_system, char *to_sector, char *to_system)
|
|
{
|
|
// Check for invalid destinations
|
|
if (to_sector == 0 || to_sector_id == 0 || to_system == 0)
|
|
{
|
|
LogMessage("FATAL ERROR! Invalid server handoff destination! Returning to source\n");
|
|
to_sector = from_sector;
|
|
to_sector_id = from_sector_id;
|
|
to_system = from_system;
|
|
}
|
|
|
|
ServerHandoff server_handoff;
|
|
memset(&server_handoff, 0, sizeof(server_handoff));
|
|
|
|
server_handoff.join = m_MasterJoin;
|
|
server_handoff.join.ToSectorID = ntohl(to_sector_id);
|
|
server_handoff.join.FromSectorID = ntohl(from_sector_id);
|
|
|
|
// Populate "FROM SECTOR" string
|
|
char *p = (char *) &server_handoff.variable_data;
|
|
*((short *) p) = strlen(from_sector);
|
|
p += 2;
|
|
strncpy(p, from_sector, strlen(from_sector));
|
|
p += strlen(from_sector);
|
|
|
|
// Populate "FROM SYSTEM" string
|
|
*((short *) p) = strlen(from_system);
|
|
p += 2;
|
|
strncpy(p, from_system, strlen(from_system));
|
|
p += strlen(from_system);
|
|
|
|
// Populate "TO SECTOR" string
|
|
*((short *) p) = strlen(to_sector);
|
|
p += 2;
|
|
strncpy(p, to_sector, strlen(to_sector));
|
|
p += strlen(to_sector);
|
|
|
|
// Populate "TO SYSTEM" string
|
|
*((short *) p) = strlen(to_system);
|
|
p += 2;
|
|
strncpy(p, to_system, strlen(to_system));
|
|
p += strlen(to_system);
|
|
|
|
size_t length = (p - (char *) &server_handoff);
|
|
|
|
LogDebug("Sending ServerHandoff, ToSectorID = %d\n", to_sector_id);
|
|
SendResponse(ENB_OPCODE_003A_SERVER_HANDOFF, (unsigned char *) &server_handoff, length);
|
|
|
|
ChangeSectorID(to_sector_id);
|
|
}
|
|
|
|
void Connection::HandleTriggerEmote()
|
|
{
|
|
TriggerEmote * emote = (TriggerEmote *) m_RecvBuffer;
|
|
|
|
SendNotifyEmote(emote->GameID, emote->Emote);
|
|
}
|
|
|
|
//TODO: Recode using new packet methods
|
|
void Connection::HandleChatStream()
|
|
{
|
|
ChatStream * chat_stream = (ChatStream *) m_RecvBuffer;
|
|
unsigned char *buffer;
|
|
unsigned char *p;
|
|
|
|
if (chat_stream->message[0] == 0x02) // Emote
|
|
{
|
|
LogMessage("Received AvatarTriggerEmote packet -- GameID=%d\n", chat_stream->GameID);
|
|
|
|
buffer = new unsigned char[chat_stream->ChatSize + 7]; // 7 = (long GameID, short ChatSize, char type)
|
|
memset(buffer, 0, chat_stream->ChatSize + 7);
|
|
|
|
*((short *) &buffer[0]) = chat_stream->ChatSize;
|
|
buffer[2] = 0x01;
|
|
*((long *) &buffer[3]) = chat_stream->GameID;
|
|
p = (unsigned char *)chat_stream;
|
|
p+=7;
|
|
memcpy(&buffer[7],p,chat_stream->ChatSize);
|
|
|
|
//SendResponse(ENB_OPCODE_005F_AVATAR_EMOTE_RESPONSE, buffer, chat_stream->ChatSize + 7);
|
|
m_Player->SendToSector(ENB_OPCODE_005F_AVATAR_EMOTE_RESPONSE, buffer, chat_stream->ChatSize + 7);
|
|
delete[] buffer;
|
|
}
|
|
else if (chat_stream->message[0] == 0x01) // Chat in Stations
|
|
{
|
|
//Commented this section out so local messages aren't sent twice (Once as local, the other as broadcast)
|
|
//short chatStringLength = *((short *)&chat_stream->message[2]);
|
|
//char broadcast[2048];
|
|
//sprintf(broadcast, "[Local] %s: %s", m_Player->Name(), &chat_stream->message[4]);
|
|
//SendMessageString(broadcast, 7);
|
|
LogDebug("ChatStream code: %d\n", chat_stream->message[0]);
|
|
}
|
|
else
|
|
{
|
|
LogMessage("ChatStream code: %d\n", chat_stream->message[0]);
|
|
LogMessage("Received Unknown ChatStream code\n");
|
|
}
|
|
}
|
|
|
|
void Connection::SendClientChatEvent(int Unknown, int Unknown2, char * FName, char * LName, char * Channel, char * Message)
|
|
{
|
|
unsigned char Packet[1024];
|
|
int Index = 0;
|
|
|
|
AddData(Packet, Unknown, Index); // Not sure what this is usualy its 0x03
|
|
AddData(Packet, Unknown2, Index); // Not sure what this is usualy its 0x00
|
|
AddDataLS(Packet, FName, Index); // First Name of Player
|
|
AddDataLS(Packet, LName, Index); // Last Name of Player
|
|
AddData(Packet, (short) 0, Index); // ? End Marker I think ?
|
|
AddDataLS(Packet, Channel, Index); // Channel it came from
|
|
AddDataLS(Packet, Message, Index); // Message
|
|
AddData(Packet, 0, Index); // ? End Marker I think ?
|
|
AddData(Packet, (short) 0, Index); // ? End Marker I think ?
|
|
|
|
|
|
if (0/*log*/) //TODO: add chat logging global
|
|
{
|
|
// Log all chat messages to the chat log.
|
|
LogChatMsg("%s->[%s]> \"%s\" (%s)\n", FName, Channel, Message, m_Player->Name());
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_00A5_CLIENT_CHAT_EVENT, (unsigned char *) Packet, Index); // Send Packet
|
|
}
|
|
|
|
void Connection::SendNotifyEmote(long game_id, long emote)
|
|
{
|
|
NotifyEmote response;
|
|
response.GameID = game_id;
|
|
response.Emote = emote;
|
|
|
|
//LogMessage("Sending NotifyEmote packet\n");
|
|
//SendResponse(ENB_OPCODE_00A2_NOTIFY_EMOTE, (unsigned char *) &response, sizeof(response));
|
|
m_Player->SendToRangeList(ENB_OPCODE_00A2_NOTIFY_EMOTE, (unsigned char *) &response, sizeof(response));
|
|
}
|
|
|
|
void Connection::HandleOption()
|
|
{
|
|
OptionPacket * myOption = (OptionPacket *) m_RecvBuffer;
|
|
|
|
LogMessage("Received Option packet -- GameID=%d OptionType=%d OptionVar=%d\n",
|
|
myOption->GameID, myOption->OptionType, myOption->OptionVar);
|
|
DumpBuffer(m_RecvBuffer,sizeof(OptionPacket));
|
|
}
|
|
|
|
// This is going to need re-coding in the same way as the Action Packet method
|
|
void Connection::HandleSelectTalkTree()
|
|
{
|
|
SelectTalkTree * packet = (SelectTalkTree *) m_RecvBuffer;
|
|
|
|
LogMessage("Received SelectTalkTree packet -- PlayerID=%x Selection=%d\n",
|
|
(packet->PlayerID & 0x00FFFFFF), packet->Selection);
|
|
|
|
if (m_ActionResponseReceived == true
|
|
&& packet->Selection == 0)
|
|
{
|
|
SendTalkTreeAction(-32);
|
|
SendTalkTreeAction(-32);
|
|
m_ActionResponseReceived = false;
|
|
return;
|
|
}
|
|
|
|
if (m_TradeWindow == true)
|
|
{
|
|
if (packet->Selection == 0)
|
|
{
|
|
SendTalkTreeAction(-32);
|
|
m_TradeWindow = false;
|
|
return;
|
|
}
|
|
m_TradeWindow = false;
|
|
}
|
|
|
|
if (m_BeaconRequest)
|
|
{
|
|
switch(packet->Selection)
|
|
{
|
|
case 0: // Tow to Base
|
|
SendTalkTreeAction(-32);
|
|
m_Player->SetDistressBeacon(false);
|
|
m_Player->TowToBase();
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 1: // Distress Beacon
|
|
SendTalkTreeAction(-32);
|
|
m_Player->SetDistressBeacon(true);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 2: // I'm OK
|
|
SendTalkTreeAction(-32);
|
|
m_Player->SetDistressBeacon(false);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 230: // Close
|
|
SendTalkTreeAction(-32);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
}
|
|
|
|
if (!m_BeaconRequest)
|
|
return;
|
|
}
|
|
|
|
|
|
if (packet->Selection != 230 && m_Player->CheckMissions(0, packet->Selection, 0, m_StarbaseTargetID))
|
|
{
|
|
m_TradeWindow = true;
|
|
if (packet->Selection == 0)
|
|
{
|
|
SendTalkTreeAction(-32); //close display
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Trade with vendor
|
|
if (packet->Selection == 0)
|
|
{
|
|
char string[] = "/happy2 Thanks for coming by my booth. May good fortune be with you.\0\0\0";
|
|
|
|
// 78 Items
|
|
long ItemTemp[128];
|
|
long ItemPrice[128];
|
|
int TotalItems = 0;
|
|
int ItemType = 14; //Default to weapons if type is not set!!
|
|
int ItemType2 = 0, ItemType3 = 0, ItemType4 = 0;
|
|
|
|
|
|
//TODO: Remove hardcoding
|
|
//just make this a bit more fun until we do.
|
|
|
|
switch (m_StarbaseTargetID)
|
|
{
|
|
//Weapons
|
|
case 1:
|
|
case 145:
|
|
ItemType = 14; // Beams
|
|
ItemType2 = 15; // Missiles
|
|
ItemType3 = 16; // Projectiles
|
|
ItemType4 = 10; // Ammo
|
|
break;
|
|
// Shields
|
|
case 46:
|
|
ItemType = 2;
|
|
break;
|
|
//junk/components (I think)
|
|
case 81:
|
|
case 160:
|
|
case 124:
|
|
case 74:
|
|
ItemType = 13;
|
|
ItemType2 = 10; //also sell missile ammo
|
|
break;
|
|
// Reactors
|
|
case 80:
|
|
ItemType = 7;
|
|
break;
|
|
|
|
//Engines
|
|
case 66:
|
|
ItemType = 6;
|
|
break;
|
|
|
|
//If we haven't got a specific ID then choose one based on ID modulus
|
|
default:
|
|
{
|
|
switch (m_StarbaseTargetID%5)
|
|
{
|
|
case 0:
|
|
ItemType = 14; // Beams
|
|
ItemType2 = 15; // Missiles
|
|
ItemType3 = 16; // Projectiles
|
|
ItemType4 = 10; // Ammo
|
|
break;
|
|
case 1:
|
|
ItemType = 2;
|
|
break;
|
|
case 2:
|
|
ItemType = 13;
|
|
ItemType2 = 16;
|
|
break;
|
|
case 3:
|
|
ItemType = 7;
|
|
break;
|
|
case 4:
|
|
ItemType = 6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ItemBase * item = 0;
|
|
int x = 0;
|
|
|
|
while (TotalItems < 50 && x < MAX_ITEMBASE_ITEMS)
|
|
{
|
|
if (item = g_ItemBaseMgr->GetItem(x))
|
|
{
|
|
if (item->ItemType() == ItemType || (ItemType2 != 0 && item->ItemType() == ItemType2)
|
|
|| (ItemType3 != 0 && item->ItemType() == ItemType3) || (ItemType4 != 0 && item->ItemType() == ItemType4))
|
|
{
|
|
m_Player->SendItemBase(item->ItemTemplateID());
|
|
ItemTemp[TotalItems] = item->ItemTemplateID();
|
|
ItemPrice[TotalItems] = item->Cost() * 2;
|
|
TotalItems++;
|
|
}
|
|
}
|
|
|
|
x++;
|
|
}
|
|
|
|
for(x=0; x<TotalItems; x++)
|
|
{
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].SetItemTemplateID(ItemTemp[x]);
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].SetStackCount(1);
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].SetStructure(1.0f);
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].SetQuality(1.0f);
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].SetPrice(ItemPrice[x]);
|
|
}
|
|
for (x=TotalItems; x<128; x++)
|
|
{
|
|
m_Player->PlayerIndex()->VendorInv.Item[x].Clear();
|
|
}
|
|
|
|
m_Player->SetPrices();
|
|
m_Player->SendAuxPlayer();
|
|
m_Player->SendAuxShip();
|
|
|
|
SendTalkTreeAction(5);
|
|
SendTalkTreeAction(3);
|
|
SendResponse(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
SendTalkTreeAction(6);
|
|
|
|
m_TradeWindow = true;
|
|
}
|
|
|
|
if (packet->Selection == 1 || packet->Selection == 230 )
|
|
{
|
|
SendTalkTreeAction(-32);
|
|
|
|
m_Player->ClearPrices();
|
|
m_Player->SendAuxPlayer();
|
|
m_Player->SendAuxShip();
|
|
}
|
|
}
|
|
|
|
void Connection::SendRelationship(long ObjectID, long Reaction, bool IsAttacking)
|
|
{
|
|
Relationship response;
|
|
response.ObjectID = ntohl(ObjectID);
|
|
response.Reaction = Reaction;
|
|
response.IsAttacking = IsAttacking ? 1 : 0;
|
|
|
|
//LogMessage("Sending Relationship packet\n");
|
|
SendResponse(ENB_OPCODE_0089_RELATIONSHIP, (unsigned char *) &response, sizeof(response));
|
|
}
|
|
|
|
void Connection::HandleGalaxyMapRequest()
|
|
{
|
|
LogMessage("Received GalaxyMap request packet\n");
|
|
SendResponse(ENB_OPCODE_2011_GALAXY_MAP, 0, 0);
|
|
//SendDataFileToClient("GalaxyMap.dat");
|
|
}
|
|
|
|
void Connection::SendGalaxyMap(char *system, char *sector, char *station)
|
|
{
|
|
struct GalaxyMap
|
|
{
|
|
long Type;
|
|
long Size;
|
|
long PlayerID;
|
|
char Variable[64];
|
|
long unknown;
|
|
};
|
|
|
|
GalaxyMap galaxy_map;
|
|
long string_length;
|
|
long size = 8; // include PlayerID and unknown
|
|
char *p = galaxy_map.Variable;
|
|
|
|
galaxy_map.Type = 4;
|
|
galaxy_map.PlayerID = m_AvatarID;
|
|
|
|
// System
|
|
strcpy(p, system);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
// Sector
|
|
strcpy(p, sector);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
// Station
|
|
strcpy(p, station);
|
|
string_length = strlen(p) + 1;
|
|
size += string_length;
|
|
p += string_length;
|
|
|
|
*((long *) p) = 375; // unknown = 375
|
|
galaxy_map.Size = size;
|
|
|
|
//LogMessage("Sending GalaxyMap packet\n");
|
|
SendResponse(ENB_OPCODE_0097_GALAXY_MAP, (unsigned char * ) &galaxy_map, size + 8);
|
|
}
|
|
|
|
void Connection::HandleDebug()
|
|
{
|
|
LogDebug("Received Debug packet\n");
|
|
}
|
|
|
|
void Connection::SendAdvancedPositionalUpdate(long object_id)
|
|
{
|
|
// NOTE: THIS IS HARD-CODED FOR PLACING THE PLAYERS SHIP IN EARTH SECTOR
|
|
// THIS TEMPORARY CODE WILL BE DELETED!
|
|
|
|
m_Player->SetOrientation(0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
|
/*
|
|
switch (m_SectorID)
|
|
{
|
|
case 1060 : // Earth - Earth Station
|
|
position[0] = 4200.0; // X
|
|
position[1] = 14300.0; // Y
|
|
position[2] = 0.0; // Z
|
|
break;
|
|
case 1052 : // Io - Nishino Research Facility
|
|
position[0] = -56400.0; // X
|
|
position[1] = 86800.0; // Y
|
|
position[2] = 750.0; // Z
|
|
break;
|
|
case 1020 : // High Earth - Loki Station
|
|
position[0] = -68310.0; // X
|
|
position[1] = -22180.0; // Y
|
|
position[2] = 0.0; // Z
|
|
break;
|
|
case 1015 : // Luna - Luna Station
|
|
position[0] = -91620.0; // X
|
|
position[1] = 105450.0; // Y
|
|
position[2] = 0.0; // Z
|
|
break;
|
|
case 1030 : // Mars Beta - Arx Prima
|
|
position[0] = -84770.0; // X
|
|
position[1] = 590.0; // Y
|
|
position[2] = 8000.0; // Z
|
|
break;
|
|
default : // arbitrary starting point
|
|
position[0] = 0.0; // X
|
|
position[1] = 5000.0; // Y
|
|
position[2] = 0.0; // Z
|
|
break;
|
|
}*/
|
|
|
|
if (m_FromSectorID > 9999)
|
|
{
|
|
// The player just left a station
|
|
// see if we had any entry coords
|
|
if (!m_Player->RestoreDockingCoords())
|
|
{
|
|
Object *station = m_ObjectMgr->FindStation(0);
|
|
Object *nearest_nav = m_Player->NearestNav();
|
|
if (nearest_nav)
|
|
{
|
|
m_Player->Face(nearest_nav);
|
|
}
|
|
if (station)
|
|
{
|
|
int offset = 0;
|
|
// Place the player's ship near the gate
|
|
switch(m_SectorID)
|
|
{
|
|
case 1060 :
|
|
offset = - 10000;
|
|
break;
|
|
default :
|
|
offset = station->Radius();
|
|
if (offset == 0)
|
|
{
|
|
offset = 4400;
|
|
}
|
|
break;
|
|
}
|
|
m_Player->SetPosition(station->PosX() + offset, station->PosY(), station->PosZ());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_SectorID < 9999)
|
|
{
|
|
// The player just went through a gate
|
|
Object *gate = m_ObjectMgr->FindGate(m_FromSectorID);
|
|
if (!gate) gate = m_ObjectMgr->FindFirstNav();
|
|
if (gate)
|
|
{
|
|
// Place the player's ship near the gate
|
|
// TODO: Move the player about 1K towards the nearest nav
|
|
// TODO: Point the players ship (orientation) towards the nearest nav
|
|
m_Player->SetPosition(gate->Position());
|
|
}
|
|
else
|
|
{
|
|
LogMessage("WARNING!! No gate or nav found in sector %s\n", m_SectorMgr->GetSectorName(m_SectorID));
|
|
m_Player->SetPosition(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Player->SetPosition(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
|
|
if (m_FromSectorID == 0 || (m_FromSectorID == m_SectorID)) // We just logged in!
|
|
{
|
|
bool success = m_Player->LoadPosition();
|
|
|
|
if (!success || (m_Player->PosX() == 0.0f && m_Player->PosY() == 0.0f && m_Player->PosZ() == 0.0f))
|
|
{
|
|
LogDebug("Cannot load postion file setting to nearest gate.\n");
|
|
|
|
//find first nav
|
|
Object *obj = m_ObjectMgr->FindFirstNav();
|
|
|
|
if (!obj)
|
|
{
|
|
obj = m_ObjectMgr->GetObjectFromID(10000);
|
|
}
|
|
|
|
if (obj)
|
|
{
|
|
m_Player->SetPosition(obj->Position());
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO: replace this with something more sensible
|
|
//we can't send the advpos until we have received a time request.
|
|
unsigned char update[] =
|
|
{
|
|
0x00, 0x00, // Bitmask
|
|
0xEF, 0x17, 0xC0, 0x07, // GameID
|
|
0xE0, 0xEB, 0xEA, 0x25, // Timestamp
|
|
0x7C, 0x6A, 0x83, 0x45, // X
|
|
0x3A, 0xFE, 0x5F, 0x46, // Y
|
|
0xB0, 0x39, 0xDE, 0x41, // Z
|
|
0x00, 0x00, 0x00, 0x00, //O1
|
|
0x00, 0x00, 0x00, 0x00, //O2
|
|
0x5B, 0xD1, 0x7F, 0x3F, //O3
|
|
0x3A, 0x82, 0x1A, 0xBD, //O4
|
|
0x05, 0x00, 0x00, 0x00 // Movement ID
|
|
};
|
|
|
|
*((long *) &update[2]) = object_id;
|
|
*((long *) &update[6]) = GetNet7TickCount();
|
|
*((float *) &update[10]) = m_Player->PosX();
|
|
*((float *) &update[14]) = m_Player->PosY();
|
|
*((float *) &update[18]) = m_Player->PosZ();
|
|
float *orientation = m_Player->Orientation();
|
|
*((float *) &update[22]) = orientation[0];
|
|
*((float *) &update[26]) = orientation[1];
|
|
*((float *) &update[30]) = orientation[2];
|
|
*((float *) &update[34]) = orientation[3];
|
|
|
|
//LogMessage("Sending AdvancedPositionalUpdate packet\n");
|
|
SendResponse(ENB_OPCODE_003E_ADVANCED_POSITIONAL_UPDATE, update, sizeof(update));
|
|
m_Player->UpdateVerbs();
|
|
}
|
|
|
|
void Connection::SendMessageString(char *msg, char color, bool log)
|
|
{
|
|
char buffer[512];
|
|
memset(buffer, 0, sizeof(buffer));
|
|
short length = strlen(msg) + 1;
|
|
*((short *) &buffer[0]) = length;
|
|
buffer[2] = color;
|
|
strcpy(&buffer[3], msg);
|
|
|
|
if (log)
|
|
{
|
|
// Log all chat messages to the chat log.
|
|
LogChatMsg("%s> \"%s\"\n", m_Player->Name(), msg);
|
|
}
|
|
|
|
SendResponse(ENB_OPCODE_001D_MESSAGE_STRING, (unsigned char *) buffer, length + 3);
|
|
}
|
|
|
|
void Connection::SendPriorityMessageString(char *msg1, char *msg2, long time, long priority)
|
|
{
|
|
unsigned char buffer[512];
|
|
int index = 0;
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
AddDataSN(buffer, msg1, index);
|
|
AddDataSN(buffer, msg2, index);
|
|
AddData(buffer, time, index);
|
|
AddData(buffer, priority, index);
|
|
|
|
SendResponse(ENB_OPCODE_0020_PRIORITY_MESSAGE, &buffer[0], index);
|
|
}
|
|
|
|
void Connection::HandleMissionDismissal()
|
|
{
|
|
MissionDismissal *dismiss = (MissionDismissal *)m_RecvBuffer;
|
|
long MissionID = ntohl(dismiss->MissionID);
|
|
long PlayerID = ntohl(dismiss->PlayerID);
|
|
|
|
m_Player->MissionDismiss(MissionID);
|
|
}
|
|
|
|
void Connection::HandleMissionForfeit() //TODO: change handling of forfeit. at the moment, we allow ppl to repeat the mission.
|
|
{
|
|
MissionDismissal *dismiss = (MissionDismissal *)m_RecvBuffer;
|
|
long MissionID = ntohl(dismiss->MissionID);
|
|
long PlayerID = ntohl(dismiss->PlayerID);
|
|
|
|
m_Player->MissionDismiss(MissionID);
|
|
}
|
|
|
|
/*
|
|
struct PetitionStuck
|
|
{
|
|
long GameID; // Player ID
|
|
long ProblemType; // see below
|
|
char Subject[]; // variable length null-terminated string
|
|
char Complaint[]; // variable length null-terminated string
|
|
char PlayerList[]; // variable length null-terminated string
|
|
};
|
|
|
|
Problem Type:
|
|
1 = I have a question about game play
|
|
2 = I am stuck, trapped, or blackholed
|
|
3 = I am having a problem with another player
|
|
|
|
23 00 Length = 35 bytes
|
|
88 00 Opcode 0x88 = PetitionStuck
|
|
EF 17 C0 07 GameID = player
|
|
03 00 00 00 ProblemType
|
|
73 75 62 6A 65 63 74 00 Subject = "Subject"
|
|
64 65 74 61 69 6C 73 00 Complaint = "Details"
|
|
50 6C 61 79 65 72 6E 61 6D 65 00 PlayerList = "Playername"
|
|
*/
|
|
|
|
void Connection::HandlePetitionStuck()
|
|
{
|
|
char *p = (char *) m_RecvBuffer;
|
|
long GameID = *((long *) p);
|
|
p += 4;
|
|
long ProblemType = *((long *) p);
|
|
p += 4;
|
|
char *Subject = p;
|
|
p += strlen(p) + 1;
|
|
char *Complaint = p;
|
|
p += strlen(p) + 1;
|
|
char *PlayerList = p;
|
|
LogMessage("Received PetitionStuck packet {PlayerID=%x ProblemType=%d}\n", GameID, ProblemType);
|
|
LogMessage("Subject=\"%s\"\n", Subject);
|
|
LogMessage("Complaint=\"%s\"\n", Complaint);
|
|
LogMessage("PlayerList=\"%s\"\n", PlayerList);
|
|
}
|
|
|
|
|
|
void Connection::HandleIncapacitanceRequest()
|
|
{
|
|
long player = *m_RecvBuffer; //we know who this is... But maybe for UDP we wouldn't have
|
|
|
|
char string[] =
|
|
"That was one heck of an explosion! Are you alright over there?\0"
|
|
"\0\3"
|
|
"\0\0\0\0"
|
|
"I need a tow\0"
|
|
"\1\0\0\0"
|
|
"Toggle distress beacon\0"
|
|
"\2\0\0\0"
|
|
"I'm OK\0";
|
|
|
|
|
|
SendResponse(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
|
|
AvatarDescription avatar;
|
|
memset(&avatar, 0, sizeof(avatar));
|
|
memcpy(&avatar.avatar_data, &m_Player->Database()->avatar, sizeof(avatar.avatar_data));
|
|
avatar.AvatarID = m_Player->GameID();
|
|
avatar.unknown3 = 1.0;
|
|
avatar.unknown4 = 1.0;
|
|
SendResponse(ENB_OPCODE_0061_AVATAR_DESCRIPTION, (unsigned char *) &avatar, sizeof(avatar));
|
|
|
|
// Send Avatar ID to show up in talk tree
|
|
m_Player->PlayerIndex()->SetPIPAvatarID(m_Player->CharacterID());
|
|
m_Player->SendAuxPlayer();
|
|
|
|
m_BeaconRequest = true;
|
|
}
|
|
|
|
void Connection::SendWarpIndex(int index)
|
|
{
|
|
SendResponse(ENB_OPCODE_009C_WARP_INDEX, (unsigned char*) &index, sizeof(index));
|
|
}
|
|
|
|
void Connection::SetInSpace(bool in_space)
|
|
{
|
|
m_Player->SetInSpace(in_space);
|
|
}
|
|
|
|
void Connection::SetActive(bool is_active)
|
|
{
|
|
m_Player->SetActive(is_active);
|
|
if (g_Debug && m_Player->AdminLevel() == 80)
|
|
{
|
|
m_Player->SendVaMessage("Connection Active: %s", is_active ? "true" : "false");
|
|
}
|
|
}
|
|
|
|
// Utility functions
|
|
|
|
|
|
// given a string of hex digits convert them into an integer value
|
|
static int _httoi(const char *value)
|
|
{
|
|
char *storage = (char*)alloca(strlen(value) + 1);
|
|
struct CHexMap
|
|
{
|
|
char chr;
|
|
int value;
|
|
};
|
|
const int HexMapL = 16;
|
|
CHexMap HexMap[HexMapL] =
|
|
{
|
|
{'0', 0}, {'1', 1},
|
|
{'2', 2}, {'3', 3},
|
|
{'4', 4}, {'5', 5},
|
|
{'6', 6}, {'7', 7},
|
|
{'8', 8}, {'9', 9},
|
|
{'A', 10}, {'B', 11},
|
|
{'C', 12}, {'D', 13},
|
|
{'E', 14}, {'F', 15}
|
|
};
|
|
strcpy(storage, value);
|
|
char *p = storage;
|
|
while (*p)
|
|
{
|
|
*p = toupper(*p);
|
|
p++;
|
|
}
|
|
char *s = storage;
|
|
int result = 0;
|
|
if (*s == '0' && *(s + 1) == 'X') s += 2;
|
|
bool firsttime = true;
|
|
while (*s != '\0')
|
|
{
|
|
bool found = false;
|
|
for (int i = 0; i < HexMapL; i++)
|
|
{
|
|
if (*s == HexMap[i].chr)
|
|
{
|
|
if (!firsttime) result <<= 4;
|
|
result |= HexMap[i].value;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) break;
|
|
s++;
|
|
firsttime = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif
|