mirror of
https://github.com/therealKyp/Earth-and-Beyond-server
synced 2026-08-13 22:23:03 -04:00
7727 lines
208 KiB
C++
7727 lines
208 KiB
C++
// PlayerConnection.cpp
|
|
|
|
#ifdef WIN32
|
|
#pragma warning(disable:4786)
|
|
#endif
|
|
|
|
#include "PlayerClass.h"
|
|
#include "ServerManager.h"
|
|
#include "ObjectManager.h"
|
|
#include "Opcodes.h"
|
|
#include "PacketMethods.h"
|
|
#include "StaticData.h"
|
|
#include "UDPConnection.h"
|
|
#include "MOBDatabase.h"
|
|
#include "WinCompatibility.h"
|
|
|
|
void Player::SetPlayerPortIP(short port, long ip_addr)
|
|
{
|
|
m_Player_IPAddr = ip_addr;
|
|
m_Player_Port = port;
|
|
}
|
|
|
|
#define RECEIVE_MESSAGE_MAX_LENGTH 256
|
|
char unknown_corpse[] = "Corpse\0";
|
|
|
|
/*void Player::RunMsgThread()
|
|
{
|
|
int length;
|
|
EnbTcpHeader *header;
|
|
unsigned char msg[RECEIVE_MESSAGE_MAX_LENGTH]; //message will be under 256 or the 'AddMessage' method will not process it
|
|
|
|
m_MsgThreadRunning = true;
|
|
|
|
while (!g_ServerShutdown)
|
|
{
|
|
while (m_RecvQueue->CheckQueue(msg, &length, RECEIVE_MESSAGE_MAX_LENGTH)) //check if there are any messages in the queue, if there are write them into the 'msg' buffer
|
|
{
|
|
//process this message
|
|
//format is opcode/length/message
|
|
header = (EnbTcpHeader*)msg;
|
|
unsigned char *data = (msg + sizeof(EnbTcpHeader));
|
|
|
|
//process opcode accordingly
|
|
HandleClientOpcode(header->opcode, header->size, data);
|
|
}
|
|
SuspendThread(m_MsgThreadHandle);
|
|
Sleep(2);
|
|
}
|
|
}*/
|
|
|
|
void Player::PulsePlayerInput()
|
|
{
|
|
int length;
|
|
EnbTcpHeader *header;
|
|
unsigned char msg[RECEIVE_MESSAGE_MAX_LENGTH]; //message will be under 256 or the 'AddMessage' method will not process it
|
|
|
|
while (m_RecvQueue->CheckQueue(msg, &length, RECEIVE_MESSAGE_MAX_LENGTH)) //check if there are any messages in the queue, if there are write them into the 'msg' buffer
|
|
{
|
|
//process this message
|
|
//format is opcode/length/message
|
|
header = (EnbTcpHeader*)msg;
|
|
unsigned char *data = (msg + sizeof(EnbTcpHeader));
|
|
|
|
//process opcode accordingly
|
|
HandleClientOpcode(header->opcode, header->size, data);
|
|
}
|
|
}
|
|
|
|
void Player::AddMessage(short opcode, short length, unsigned char *data)
|
|
{
|
|
if (!m_MsgThreadRunning)
|
|
{
|
|
LogMessage("ERROR!: Message thread for %s not running!!\n", Name());
|
|
return;
|
|
}
|
|
|
|
unsigned char pData[RECEIVE_MESSAGE_MAX_LENGTH];
|
|
|
|
if (length + 4 > RECEIVE_MESSAGE_MAX_LENGTH)
|
|
{
|
|
LogMessage("Recv message overflow: length = %d\n", length);
|
|
return;
|
|
}
|
|
|
|
*((short*) &pData[0]) = length;
|
|
*((short*) &pData[2]) = opcode;
|
|
memcpy(pData + sizeof(short)*2, data, length);
|
|
|
|
m_RecvQueue->Add(pData, length+sizeof(EnbTcpHeader), GameID());
|
|
}
|
|
|
|
void Player::SendOpcode(short opcode, unsigned char *data, long length, bool issue)
|
|
{
|
|
if (!this) return;
|
|
|
|
if (m_LoginConnection && m_LoginConnection->GameID() == GameID())
|
|
{
|
|
m_LoginConnection->SendResponse(opcode, data, length);
|
|
}
|
|
else if (m_UDPConnection)
|
|
{
|
|
m_LoginConnection = 0;
|
|
if (!issue)
|
|
{
|
|
CacheOpcode(opcode, data, (u16)length);
|
|
}
|
|
else
|
|
{
|
|
m_UDPConnection->SendOpcode(opcode, this, data, length, m_Player_IPAddr, m_Player_Port, m_PacketSequenceNum);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::CommitCacheToQueue()
|
|
{
|
|
m_SendQueue->Add(m_QueueCache, m_QueueCacheIndex, GameID());
|
|
m_QueueCacheIndex = 0;
|
|
}
|
|
|
|
void Player::CacheOpcode(short opcode, unsigned char *data, u16 length)
|
|
{
|
|
if ( m_QueueCacheIndex < 0 || m_QueueCacheIndex >= MAXIMUM_PACKET_CACHE) m_QueueCacheIndex = 0;
|
|
|
|
if ( m_QueueCacheIndex > 0 && (m_QueueCacheIndex + length + 4) > PERIODIC_CACHE_SEND_SIZE )
|
|
{
|
|
//need to commit existing packet to buffer and start again
|
|
CommitCacheToQueue();
|
|
}
|
|
|
|
u8 *ptr = m_QueueCache + m_QueueCacheIndex;
|
|
|
|
//write header
|
|
*((u16 *) &ptr[0]) = (u16) length + sizeof(short)*2;
|
|
*((short *) &ptr[2]) = opcode;
|
|
|
|
ptr += 4;
|
|
|
|
//write data
|
|
memcpy(ptr, data, length);
|
|
|
|
m_QueueCacheIndex += length + sizeof(short)*2;
|
|
}
|
|
|
|
void Player::SendPacketCache()
|
|
{
|
|
m_WeaponsPerTick = 0;
|
|
|
|
//first process all our inputs
|
|
PulsePlayerInput();
|
|
|
|
if (m_LoginConnection && m_LoginConnection->GameID() == GameID())
|
|
{
|
|
m_LoginConnection->SetLoginHandoff(true);
|
|
m_LoginConnection->PulseConnectionOutput(true); //empty the TCP queue
|
|
}
|
|
else
|
|
{
|
|
int size;
|
|
//commit current cache to queue if any
|
|
if (m_QueueCacheIndex > 0) CommitCacheToQueue();
|
|
|
|
m_Mutex.Lock();
|
|
|
|
//see if there's anything we can send
|
|
if (m_SendQueue->CheckQueue(m_PacketCache, &size, MAXIMUM_PACKET_CACHE, m_PacketSequenceNum))
|
|
{
|
|
#if 0
|
|
//packet drop out simulation testing
|
|
if (rand()%5 == 0)
|
|
{
|
|
LogMessage("Dropped packet %x\n", m_PacketSequenceNum);
|
|
m_PacketSequenceNum++;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SendOpcode(ENB_OPCODE_2016_PACKET_SEQUENCE, m_PacketCache, size, true);
|
|
m_PacketSequenceNum++;
|
|
}
|
|
}
|
|
|
|
m_Mutex.Unlock();
|
|
}
|
|
m_OpcodeResends = 0;
|
|
}
|
|
|
|
void Player::ReSendOpcodes(unsigned char *data)
|
|
{
|
|
long packet_num = *((short*) &data[0]);
|
|
long opcode_count = *((short*) &data[4]);
|
|
int size;
|
|
|
|
if (m_OpcodeResends > 5)
|
|
{
|
|
return; //don't resend any more than 5 requests per tick
|
|
}
|
|
|
|
LogMessage("Opcode re-send start at #%x, count %x\n", packet_num, opcode_count);
|
|
|
|
if (opcode_count > 2)
|
|
{
|
|
packet_num += opcode_count - 2;
|
|
opcode_count = 2;
|
|
}
|
|
|
|
//see if any of these packets exist, send if they do, otherwise send a blank
|
|
while (opcode_count > 0 && m_UDPConnection)
|
|
{
|
|
m_Mutex.Lock();
|
|
if (m_SendQueue->RetreiveMessage(m_PacketCache, &size, MAXIMUM_PACKET_CACHE, packet_num, GameID()))
|
|
{
|
|
m_UDPConnection->SendOpcode(ENB_OPCODE_2016_PACKET_SEQUENCE, this, m_PacketCache, size, m_Player_IPAddr, m_Player_Port, packet_num);
|
|
}
|
|
else
|
|
{
|
|
m_UDPConnection->SendOpcode(ENB_OPCODE_2016_PACKET_SEQUENCE, this, 0, 0, m_Player_IPAddr, m_Player_Port, packet_num);
|
|
}
|
|
m_Mutex.Unlock();
|
|
opcode_count--;
|
|
packet_num++;
|
|
m_OpcodeResends++;
|
|
}
|
|
}
|
|
|
|
void Player::HandleClientOpcode(short opcode, short bytes, unsigned char *data)
|
|
{
|
|
switch (opcode)
|
|
{
|
|
case ENB_OPCODE_0002_LOGIN:
|
|
HandleLogin(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0006_START_ACK :
|
|
HandleStartAck(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0012_TURN:
|
|
HandleTurn(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0013_TILT:
|
|
HandleTilt(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0014_MOVE :
|
|
HandleMove(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0017_REQUEST_TARGET :
|
|
HandleRequestTarget(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0018_REQUEST_TARGETS_TARGET :
|
|
HandleRequestTargetsTarget(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_001A_DEBUG :
|
|
HandleDebug(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0027_INVENTORY_MOVE:
|
|
HandleInventoryMove(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0029_ITEM_STATE:
|
|
HandleItemState(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_002C_ACTION :
|
|
case ENB_OPCODE_002D_ACTION2 :
|
|
HandleAction(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_002E_OPTION :
|
|
HandleOption(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0033_CLIENT_CHAT :
|
|
HandleClientChat(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0044_REQUEST_TIME :
|
|
HandleRequestTime(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_004E_STARBASE_REQUEST :
|
|
HandleStarbaseRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0051_SKILL_STRING_RQ:
|
|
HandleSkillStringRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0055_SELECT_TALK_TREE :
|
|
HandleSelectTalkTree(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0057_SKILL_UP:
|
|
HandleSkillAction(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0058_SKILL_ABILITY:
|
|
HandleSkillAbility(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_005A_VERB_REQUEST:
|
|
HandleVerbRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_005D_EQUIP_USE :
|
|
HandleEquipUse(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_005E_AVATAR_EMOTE:
|
|
HandleChatStream(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0079_MANUFACTURE_ITEM_CATAGORY:
|
|
HandleManufactureTerminal(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_007A_MANUFACTURE_ITEM_CATAGORY :
|
|
HandleManufactureCategorySelection(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_007B_MANUFACTURE_ITEM_ID :
|
|
HandleManufactureSetItem(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_007C_REFINERY_ITEM_ID :
|
|
HandleRefineSetItem(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_007E_MANUFACTURE_ACTION:
|
|
HandleManufactureAction(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0080_MANUFACTURE_TECH_LEVEL_FILTER:
|
|
HandleManufactureLevelFilter(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0086_MISSION_FORFEIT:
|
|
HandleMissionForfeit(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0087_MISSION_DISMISSAL:
|
|
HandleMissionDismissal(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0088_PETITION_STUCK:
|
|
HandlePetitionStuck(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_008D_INCAPACITANCE_REQUEST:
|
|
HandleIncapacitanceRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_0098_GALAXY_MAP_REQUEST :
|
|
HandleGalaxyMapRequest();
|
|
break;
|
|
|
|
case ENB_OPCODE_009B_WARP:
|
|
HandleWarp(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_009D_STARBASE_AVATAR_CHANGE :
|
|
HandleStarbaseAvatarChange(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_009F_STARBASE_ROOM_CHANGE :
|
|
HandleStarbaseRoomChange(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_00A1_TRIGGER_EMOTE :
|
|
HandleTriggerEmote(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_00A3_CLIENT_CHAT_REQUEST :
|
|
HandleClientChatRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_00B9_LOGOFF_REQUEST :
|
|
HandleLogoffRequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_00BC_CTA_REQUEST :
|
|
HandleCTARequest(data);
|
|
break;
|
|
|
|
case ENB_OPCODE_00C0_CONFIRMED_ACTION_RESPONSE:
|
|
//ProcessConfirmedActionOffer(data);
|
|
break;
|
|
|
|
//resend lost/dropped opcodes
|
|
case ENB_OPCODE_2017_RESEND_PACKET_SEQUENCE:
|
|
ReSendOpcodes(data);
|
|
break;
|
|
|
|
default:
|
|
LogMessage("Bad opcode for player 0x%08x '%s': %x\n", GameID(), Name(), opcode);
|
|
break;
|
|
}
|
|
|
|
SetLastAccessTime(GetNet7TickCount());
|
|
}
|
|
|
|
void Player::HandleLoginStage2()
|
|
{
|
|
LogMessage("Login stage2 for %s\n", Name());
|
|
m_SectorMgr->HandleSectorLogin2(this);
|
|
SetActive(true);
|
|
}
|
|
|
|
void Player::HandleLogin(unsigned char *data)
|
|
{
|
|
Login * login = (Login *) data;
|
|
|
|
m_MasterJoin = login->join_data;
|
|
|
|
m_SentStart = false;
|
|
|
|
long sector_id = ntohl(m_MasterJoin.ToSectorID);
|
|
PlayerIndex()->SetSectorNum(sector_id);
|
|
m_FromSectorID = ntohl(m_MasterJoin.FromSectorID);
|
|
|
|
// Obtain the sector manager for the specified sector
|
|
m_SectorMgr = g_ServerMgr->GetSectorManager(sector_id);
|
|
|
|
if (!m_SectorMgr)
|
|
{
|
|
LogMessage("HandleLogin: Missing SectorManager for sector %d\n", sector_id);
|
|
}
|
|
else
|
|
{
|
|
//set up the player with a pointer to its sector manager and object manager
|
|
SetObjectManager(m_SectorMgr->GetObjectManager());
|
|
|
|
SectorReset();
|
|
SectorLogin();
|
|
|
|
// Set the client time
|
|
SendClientSetTime(login->TimeSent);
|
|
|
|
// Send the sector content to the client - NB AddPlayer must occur before SectorLogin
|
|
m_SectorMgr->HandleSectorLogin(this);
|
|
|
|
SaveData();
|
|
}
|
|
}
|
|
|
|
void Player::SendClientSetTime(long TimeSent)
|
|
{
|
|
ClientSetTime data;
|
|
data.ClientSent = TimeSent;
|
|
data.ServerReceived = GetNet7TickCount();
|
|
data.ServerSent = data.ServerReceived;
|
|
|
|
SendOpcode(ENB_OPCODE_0034_CLIENT_SET_TIME, (unsigned char*) &data, sizeof(data));
|
|
}
|
|
|
|
void Player::SendStarbaseSet(char action, char exit_mode)
|
|
{
|
|
StarbaseSet starbase_set;
|
|
memset(&starbase_set, 0, sizeof(starbase_set));
|
|
starbase_set.StarbaseID = PlayerIndex()->GetSectorNum();
|
|
starbase_set.Action = action;
|
|
starbase_set.ExitMode = exit_mode;
|
|
|
|
SendOpcode(ENB_OPCODE_004F_STARBASE_SET, (unsigned char *) &starbase_set, sizeof(starbase_set));
|
|
}
|
|
|
|
long Player::TryLoungeFile(long sector_id)
|
|
{
|
|
long return_sector = sector_id;
|
|
char old_path[MAX_PATH];
|
|
char lounge_npc[MAX_PATH];
|
|
|
|
sprintf(lounge_npc, "LoungeNPC_%ld.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 Player::SendDataFileToClient(const char *filename, long avatar_id)
|
|
{
|
|
char old_path[MAX_PATH];
|
|
if (m_LoginConnection)
|
|
{
|
|
SendDataFileToClientTCP(filename, avatar_id);
|
|
return;
|
|
}
|
|
|
|
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 < UDP_BUFFER_SEND_SIZE + sizeof(EnbUdpHeader)))
|
|
{
|
|
fseek(f,0,SEEK_SET);
|
|
char * buffer = (char*)&m_UDPSendBuffer[0]; //use actual send buffer
|
|
fread(buffer + sizeof(EnbUdpHeader), 1, length, f);
|
|
|
|
*((short*) &buffer[0]) = (short)length;
|
|
*((short*) &buffer[2]) = ENB_OPCODE_2010_DATA_FILE;
|
|
*((long *) &buffer[4]) = GameID();
|
|
|
|
if (avatar_id)
|
|
{
|
|
*((long *) &buffer[12]) = avatar_id;
|
|
}
|
|
|
|
//DumpBuffer((unsigned char*)buffer, length);
|
|
|
|
m_UDPConnection->UDP_Send(buffer, length, m_Player_IPAddr, m_Player_Port);
|
|
}
|
|
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 Player::SendDataFileToClientTCP(const 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))
|
|
{
|
|
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_LoginConnection->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 Player::SendConfirmedActionOffer()
|
|
{
|
|
unsigned char action_data[] =
|
|
{
|
|
0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x65,
|
|
0x07, 0x00, 0x4d, 0x65,
|
|
0x73, 0x73, 0x61, 0x67, 0x65
|
|
};
|
|
|
|
SendOpcode(ENB_OPCODE_00BE_CONFIRMED_ACTION_OFFER, action_data, sizeof(action_data));
|
|
SendClientSound("push_mission_alert_sound", 2, 0);
|
|
}
|
|
|
|
void Player::HandleActionResponse(unsigned char *data)
|
|
{
|
|
long player_id = ntohl(*((long *) &data[0]));
|
|
if (player_id == GameID())
|
|
{
|
|
m_ActionResponseReceived = true;
|
|
ProcessConfirmedActionOffer();
|
|
}
|
|
}
|
|
|
|
void Player::ProcessConfirmedActionOffer()
|
|
{
|
|
int length;
|
|
char buffer[256];
|
|
memset(&buffer, 0, 256);
|
|
|
|
if (m_ActionResponseReceived == false)
|
|
{
|
|
SendConfirmedActionOffer();
|
|
}
|
|
else
|
|
{
|
|
//TODO: re-vamp push messages, change Proxy version to match expected
|
|
length = _snprintf(buffer,256,"Hi %s, there is a new version of Net7Proxy out now (v0.95), You need to download and install it.\
|
|
this version of Net7Proxy will expire within a week or so.\nCheers, TB.", Name());
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) buffer, length+3);
|
|
|
|
{
|
|
AvatarDescription avatar;
|
|
memset(&avatar, 0, sizeof(avatar));
|
|
memcpy(&avatar.avatar_data, &Database()->avatar, sizeof(avatar.avatar_data));
|
|
avatar.AvatarID = GameID();
|
|
avatar.unknown3 = 1.0;
|
|
avatar.unknown4 = 1.0;
|
|
SendOpcode(ENB_OPCODE_0061_AVATAR_DESCRIPTION, (unsigned char *) &avatar, sizeof(avatar));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::SendObjectToObjectLinkedEffect(Object *target, Object *source, short effect1, short effect2, float speedup)
|
|
{
|
|
unsigned char link_data[128];
|
|
memset(link_data,0,128);
|
|
int index = 0;
|
|
|
|
if (!m_SectorMgr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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
|
|
|
|
SendOpcode(ENB_OPCODE_000E_OBJECT_TO_OBJECT_LINKED_EFFECT, link_data, index);
|
|
}
|
|
|
|
void Player::SendClientSound(const 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);
|
|
|
|
SendOpcode(ENB_OPCODE_006A_CLIENT_SOUND, (unsigned char *) &packet[0], index);
|
|
}
|
|
|
|
void Player::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);
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_0009_OBJECT_EFFECT, effect, index);
|
|
}
|
|
|
|
void Player::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 */
|
|
|
|
if (!m_SectorMgr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
SendOpcode(ENB_OPCODE_000A_POINT_EFFECT, point_data, sizeof(point_data));
|
|
}
|
|
|
|
void Player::SendClientType(long client_type)
|
|
{
|
|
//LogMessage("Sending ClientType packet\n");
|
|
SendOpcode(ENB_OPCODE_003C_CLIENT_TYPE, (unsigned char *) &client_type, sizeof(client_type));
|
|
}
|
|
|
|
void Player::SendStart(long start_id)
|
|
{
|
|
m_SentStart = true;
|
|
//LogMessage("Sending Start packet\n");
|
|
SendOpcode(ENB_OPCODE_0005_START, (unsigned char *) &start_id, sizeof(start_id));
|
|
}
|
|
|
|
void Player::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");
|
|
SendOpcode(ENB_OPCODE_002B_SET_BBOX, (unsigned char *) &bbox, sizeof(bbox));
|
|
}
|
|
|
|
void Player::SendSetZBand(float min, float max)
|
|
{
|
|
SetZBand zband;
|
|
zband.Min = min;
|
|
zband.Max = min;
|
|
|
|
//LogMessage("Sending SetZBand packet\n");
|
|
SendOpcode(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 Player::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;
|
|
|
|
SendOpcode(ENB_OPCODE_0099_NAVIGATION, (unsigned char *) &navigation, sizeof(navigation));
|
|
}
|
|
|
|
void Player::SendCreateAttachment(int parent, int child, int slot)
|
|
{
|
|
CreateAttachment attachment;
|
|
attachment.Parent_ID = ntohl(parent);
|
|
attachment.Child_ID = ntohl(child);
|
|
attachment.Slot = ntohl(slot);
|
|
|
|
SendOpcode(ENB_OPCODE_004A_CREATE_ATTACHMENT, (unsigned char *) &attachment, sizeof(attachment));
|
|
}
|
|
|
|
void Player::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 = (short)decal_count;
|
|
for (int i = 0; i < decal_count; i++)
|
|
{
|
|
decal.Item[i].Index = i + 1;
|
|
decal.Item[i].decal_id = decal_id;
|
|
decal.Item[i].HSV[0] = 1.0f;
|
|
decal.Item[i].HSV[1] = 1.0f;
|
|
decal.Item[i].HSV[2] = 1.0f;
|
|
decal.Item[i].opacity = 1.0f;
|
|
}
|
|
|
|
size_t size = ((char *) &decal.Item[decal_count]) - ((char *) &decal);
|
|
|
|
SendOpcode(ENB_OPCODE_0010_DECAL, (unsigned char *) &decal, size);
|
|
}
|
|
|
|
void Player::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);
|
|
|
|
SendOpcode(ENB_OPCODE_00B2_NAME_DECAL, (unsigned char *) &name_decal, sizeof(name_decal));
|
|
}
|
|
|
|
void Player::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];
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_0040_CONSTANT_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Player::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;
|
|
|
|
Player *leader = g_PlayerMgr->GetPlayer(leader_id);
|
|
|
|
//TODO: work out way of smoothing out warp drive.
|
|
// plan: send 2 of these formation updates after warp drive kicks in to get orientation locked
|
|
// then just do normal warp updates
|
|
// every time we change direction, repeat the above.
|
|
|
|
SendOpcode(ENB_OPCODE_0041_FORMATION_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Player::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];
|
|
|
|
SendOpcode(ENB_OPCODE_0008_SIMPLE_POSITIONAL_UDPATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Player::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;
|
|
|
|
SendOpcode(ENB_OPCODE_003F_PLANET_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Player::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;
|
|
|
|
SendOpcode(ENB_OPCODE_0046_COMPONENT_POSITIONAL_UPDATE, (unsigned char *) &update, sizeof(update));
|
|
}
|
|
|
|
void Player::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;
|
|
}
|
|
|
|
int length = 2 + 4 * index;
|
|
SendOpcode(ENB_OPCODE_003E_ADVANCED_POSITIONAL_UPDATE, (unsigned char *) &packet, length);
|
|
|
|
//is this to ourselves?
|
|
if (this->GameID() == object_id)
|
|
{
|
|
_sleep(1);
|
|
}
|
|
}
|
|
|
|
void Player::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);
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_000B_OBJECT_TO_OBJECT_EFFECT, effect, index);
|
|
}
|
|
|
|
void Player::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");
|
|
SendOpcode(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 Player::SendInitRenderState(long game_id, unsigned long render_state_id)
|
|
{
|
|
InitRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;
|
|
|
|
SendOpcode(ENB_OPCODE_002F_INIT_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Player::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");
|
|
SendOpcode(ENB_OPCODE_0031_ACTIVATE_NEXT_RENDER_STATE, (unsigned char *) &state, sizeof(state));
|
|
}
|
|
|
|
void Player::SendDeactivateRenderState(long game_id)
|
|
{
|
|
/*ActivateRenderState state;
|
|
|
|
state.GameID = game_id;
|
|
state.RenderStateID = render_state_id;*/
|
|
|
|
//LogMessage("Sending ActivateRenderState packet\n");
|
|
SendOpcode(ENB_OPCODE_0032_DEACTIVATE_RENDER_STATE, (unsigned char *) &game_id, sizeof(game_id));
|
|
}
|
|
|
|
void Player::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");
|
|
SendOpcode(ENB_OPCODE_0004_CREATE, (unsigned char *) &create, sizeof(create));
|
|
}
|
|
|
|
void Player::HandleSkillStringRequest(unsigned char *data)
|
|
{
|
|
ClientSkillsRequest * request = (ClientSkillsRequest *) data;
|
|
|
|
//Loot item
|
|
//not sure if this packet is used for anything other than looting
|
|
|
|
//check we're targetting a HUSK
|
|
ObjectManager *om = GetObjectManager();
|
|
Object *obj = (0);
|
|
if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
//TODO: set and check loot timer.
|
|
if (obj && obj->ObjectType() == OT_HUSK)
|
|
{
|
|
//Now check no-one else is looting this object
|
|
Player *player = obj->CheckResourceLock();
|
|
if (player && player != this)
|
|
{
|
|
SendVaMessage("%s currently being looted by %s", obj->Name(), player->Name());
|
|
}
|
|
else
|
|
{
|
|
SendClientSound("coin.wav",0, 0);
|
|
long id = ntohl(obj->GameID());
|
|
SendOpcode(ENB_OPCODE_008C_LOOT_HULK_PERMISSION, (unsigned char *)&id, sizeof(long));
|
|
//check if MOB loot is empty
|
|
if (obj->ResourceRemains() == 0.0f)
|
|
{
|
|
obj->SendObjectDrain(-1);
|
|
}
|
|
else
|
|
{
|
|
m_ProspectWindow = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::HandleStartAck(unsigned char *data)
|
|
{
|
|
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
|
|
SendLoginCamera();
|
|
}
|
|
|
|
void Player::HandleRequestTime(unsigned char *data)
|
|
{
|
|
LogDebug("Received RequestTime packet\n");
|
|
|
|
// Set the client time
|
|
SendClientSetTime(*((long *) data));
|
|
}
|
|
|
|
//TODO: recode this so it doesn't requre new/delete
|
|
//maybe allocate chat buffers, and re-size them if necessary
|
|
void Player::HandleClientChatRequest(unsigned char *data)
|
|
{
|
|
ClientChatRequest * request = (ClientChatRequest *) data;
|
|
|
|
//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)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.ChatSendPrivate(GameID(), string1, string3);
|
|
}
|
|
|
|
if (request->unknown1 == 0) // Channel Message
|
|
{
|
|
//LogMessage("ClientChatRequest: SendToChannel: %s Message: %s\n", string2, string3);
|
|
if (string3[0] == '/')
|
|
{
|
|
HandleSlashCommands(string3);
|
|
}
|
|
else
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.ChatSendChannel(GameID(), string2, string3);
|
|
}
|
|
}
|
|
|
|
if (length1)
|
|
{
|
|
delete [] string1;
|
|
}
|
|
if (length2)
|
|
{
|
|
delete [] string2;
|
|
}
|
|
if (length3)
|
|
{
|
|
delete [] string3;
|
|
}
|
|
}
|
|
|
|
void Player::HandleTurn(unsigned char *data)
|
|
{
|
|
struct PacketTurn {
|
|
long GameID;
|
|
float Intensity;
|
|
} ATTRIB_PACKED;
|
|
|
|
PacketTurn * Turning = (PacketTurn *) data;
|
|
|
|
if (!WarpDrive())
|
|
{
|
|
AbortProspecting(true,false);
|
|
Turn(Turning->Intensity);
|
|
}
|
|
}
|
|
|
|
void Player::HandleTilt(unsigned char *data)
|
|
{
|
|
struct PacketTurn {
|
|
long GameID;
|
|
float Intensity;
|
|
} ATTRIB_PACKED;
|
|
|
|
PacketTurn * Turning = (PacketTurn *) data;
|
|
|
|
if (!WarpDrive())
|
|
{
|
|
AbortProspecting(true,false);
|
|
Tilt(Turning->Intensity);
|
|
}
|
|
}
|
|
|
|
void Player::HandleMove(unsigned char *data)
|
|
{
|
|
MovePacket * Movement = (MovePacket *) data;
|
|
|
|
if (!WarpDrive())
|
|
{
|
|
AbortProspecting(true,false);
|
|
|
|
// Break formation if we are in a group & formed
|
|
if (GroupID() != -1)
|
|
{
|
|
// If we are the leader we can move the whole group
|
|
if (g_ServerMgr->m_PlayerMgr.GetMemberID(this->GroupID(), 0) != this->GameID())
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.LeaveFormation(GameID());
|
|
}
|
|
}
|
|
|
|
if (Movement->type == 4)
|
|
{
|
|
SendContrailsRL(false);
|
|
g_ServerMgr->m_PlayerMgr.FormationEngineOperation(this, false);
|
|
}
|
|
else
|
|
{
|
|
SendContrailsRL(true);
|
|
g_ServerMgr->m_PlayerMgr.FormationEngineOperation(this, true);
|
|
}
|
|
|
|
Move(Movement->type);
|
|
}
|
|
}
|
|
|
|
void Player::HandleWarp(unsigned char *data)
|
|
{
|
|
WarpPacket * warp = (WarpPacket *) data;
|
|
|
|
if (WarpDrive())
|
|
{
|
|
TerminateWarpGroup(true);
|
|
}
|
|
else
|
|
{
|
|
// Make sure we are both in formation & Group leader
|
|
if (g_ServerMgr->m_PlayerMgr.CheckGroupFormation(this) && g_ServerMgr->m_PlayerMgr.GetMemberID(this->GroupID(), 0) == this->GameID())
|
|
{
|
|
// Start up warps if you are in a formation
|
|
for(int x=0;x<6;x++)
|
|
{
|
|
int PlayerID = g_ServerMgr->m_PlayerMgr.GetMemberID(this->GroupID(), x);
|
|
if (PlayerID > 0)
|
|
{
|
|
Player* pid = g_ServerMgr->m_PlayerMgr.GetPlayer(PlayerID);
|
|
|
|
if (g_ServerMgr->m_PlayerMgr.CheckGroupFormation(pid))
|
|
{
|
|
pid->SendContrailsRL(false);
|
|
pid->SetupWarpNavs(warp->Navs, warp->TargetID);
|
|
pid->PrepareForWarp();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Break formation if we are in a group & formed
|
|
if (GroupID() != -1)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.LeaveFormation(GameID());
|
|
}
|
|
SendContrailsRL(false);
|
|
LogDebug("Warp Navs: %ld, GameID=%d (%s)\n", warp->Navs, (warp->GameID & 0x00FFFFFF), Name());
|
|
SetupWarpNavs(warp->Navs, warp->TargetID);
|
|
PrepareForWarp();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::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;
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
|
|
void Player::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);
|
|
|
|
SendOpcode(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 with Net7Proxy so it's optimal
|
|
void Player::SendHuskContent(Object *husk)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (husk)
|
|
{
|
|
contents_already_sent = husk->GetIndex(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[1024];
|
|
int index = 0;
|
|
int x;
|
|
|
|
long length = husk->NameLen();
|
|
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);
|
|
SendItemBase(slot->item->ItemTemplateID());
|
|
}
|
|
else
|
|
{
|
|
AddBuffer(aux_data, filler, 7, index);
|
|
}
|
|
}
|
|
|
|
for (x = 0; x < 40-MAX_ITEMS_PER_RESOURCE; x++)
|
|
{
|
|
AddBuffer(aux_data, filler, 7, index);
|
|
}
|
|
|
|
//set length
|
|
*((short *) &aux_data[4]) = index-8;
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, index);
|
|
husk->SetIndex(ResourceSendList());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::SendHuskName(Object *husk)
|
|
{
|
|
unsigned char aux_data[256];
|
|
memset(aux_data, 0, 256);
|
|
int index = 0;
|
|
|
|
char *name = unknown_corpse;
|
|
int length = 7;
|
|
|
|
if (husk->Name())
|
|
{
|
|
name = husk->Name();
|
|
length = husk->NameLen();
|
|
}
|
|
|
|
AddData(aux_data, husk->GameID(), index);
|
|
AddData(aux_data, (short)(length+10), index); // Lengh of Aux Packet
|
|
AddData(aux_data, (long) (0x03E01601), index);
|
|
AddData(aux_data, (short)(length), index);
|
|
AddDataS(aux_data, name, index);
|
|
AddData(aux_data, (long)0x05050505, index);
|
|
|
|
if (index >= 256)
|
|
{
|
|
LogMessage("**ERROR**: HuskNameIndex overflow error, %s, index len = %d\n", name, index);
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, index);
|
|
}
|
|
|
|
void Player::SendMobName(Object *mob)
|
|
{
|
|
unsigned char packet[340];
|
|
int index = 0;
|
|
|
|
unsigned char epilogue[] =
|
|
{
|
|
0x05, 0x05, 0x05, 0x05,
|
|
0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x3B, 0x00, //AUX length [4]
|
|
0x01,
|
|
0x16, 0x30, 0x00, 0x40, 0x00, 0x00, 0x0C, 0x80, 0x03,
|
|
0x00, 0xBE, 0x40, 0xF8, 0xC0, 0x07,
|
|
};
|
|
|
|
AddData (packet, (long)mob->GameID(), index);
|
|
AddBuffer(packet, aux_data, sizeof(aux_data), index);
|
|
AddDataLS(packet, mob->Name(), index);
|
|
AddData (packet, (float)mob->GetHullLevel(), index);
|
|
AddData (packet, (float)mob->GetStartHullLevel(), index);
|
|
AddData (packet, (long)mob->Level(), index);
|
|
AddBuffer(packet, epilogue, sizeof(epilogue), index);
|
|
|
|
*((short *) &packet[4]) = index - 6;
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, packet, index);
|
|
}
|
|
|
|
void Player::SendSimpleAuxName(Object *obj)
|
|
{
|
|
int length = obj->NameLen();
|
|
char *packet = (char*)_alloca(length+10);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = length + 4;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x12;
|
|
*((short *) &packet[8]) = length;
|
|
strncpy(&packet[10], obj->Name(), length);
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length+10);
|
|
}
|
|
|
|
void Player::SendAuxNameSignature(Object *obj)
|
|
{
|
|
char *name;
|
|
char nav = 0;
|
|
if (obj->IsNav() || obj->ObjectType() == OT_FIELD)
|
|
{
|
|
if (obj->Name() != 0)
|
|
{
|
|
name = obj->Name();
|
|
}
|
|
nav = 1;
|
|
}
|
|
|
|
int length = strlen(name);
|
|
char *packet = (char*)_alloca(length + 15);
|
|
*((long *) packet) = obj->GameID();
|
|
*((short *) &packet[4]) = length + 9;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x72;
|
|
*((short *) &packet[8]) = length;
|
|
strncpy(&packet[10], name, length);
|
|
int i = 10 + length;
|
|
packet[i++] = nav;
|
|
*((float *) &packet[i]) = obj->Signature();
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length+15);
|
|
}
|
|
|
|
void Player::SendAuxNameResource(Object *obj)
|
|
{
|
|
char packet[256];
|
|
char *name = unknown_corpse;
|
|
int length = 7;
|
|
|
|
if (!obj->Name()) Sleep(50); //tiny delay here seems to help if name is unknown.
|
|
|
|
if (obj->Name())
|
|
{
|
|
name = obj->Name();
|
|
length = obj->NameLen();
|
|
}
|
|
|
|
*((long *) &packet[0]) = obj->GameID();
|
|
*((short *) &packet[4]) = length + 5;
|
|
packet[6] = 0x01;
|
|
packet[7] = 0x16;
|
|
packet[8] = 0x04;
|
|
*((short *) &packet[9]) = length;
|
|
strncpy(&packet[11], name, length);
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, length + 11);
|
|
}
|
|
|
|
void Player::UnSetTarget(long GameID)
|
|
{
|
|
if (ShipIndex()->GetTargetGameID() == GameID)
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
//LogMessage("Sending SetTarget packet\n");
|
|
SendSetTarget(0, -1);
|
|
|
|
ShipIndex()->SetTargetGameID(-1);
|
|
SendAuxShip();
|
|
BlankVerbs();
|
|
}
|
|
}
|
|
|
|
void Player::ActivateProspectBeam(long player_id, long target_id, const 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);
|
|
}
|
|
|
|
void Player::SendPushMessage(const char *msg1, const 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);
|
|
|
|
SendOpcode(ENB_OPCODE_0022_PUSH_MESSAGE, pptr, index);
|
|
}
|
|
|
|
void Player::SetResourceDrainLevel(Object *obj, long slot)
|
|
{
|
|
unsigned long slot_index = ((0x10 << slot) | 0x02); //slot index calc
|
|
u16 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();
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, length); //this seems to initiate resource collapse or drains the resource according to last float val
|
|
}
|
|
|
|
void Player::SetHuskDrainLevel(Object *obj, long slot)
|
|
{
|
|
unsigned long slot_index = ((0x10 << slot) | 0x02); //slot index calc
|
|
unsigned char packet[128];
|
|
memset(packet,0,128);
|
|
unsigned char *pptr = &packet[0];
|
|
int index = 0;
|
|
|
|
unsigned char aux_data[] =
|
|
{
|
|
0x01, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00
|
|
} ;
|
|
|
|
AddData(pptr, obj->GameID(), index);
|
|
AddData(pptr, short(0), index);
|
|
AddBuffer(pptr, aux_data, 11, index);
|
|
AddData(pptr, 0xFFFFFFFE, index);
|
|
AddData(pptr, long(0), index);
|
|
|
|
*((long *) &pptr[9]) = slot_index;
|
|
*((short *) &pptr[4]) = (index - 6); //set info length
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, pptr, index);
|
|
}
|
|
|
|
void Player::RemoveObject(long object_id)
|
|
{
|
|
UnSetTarget(object_id);
|
|
SendOpcode(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 Player::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;
|
|
|
|
SendOpcode(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?
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
ShipIndex()->SetTargetGameID(0);
|
|
SendAuxShip();
|
|
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;
|
|
SendOpcode(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?
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Player::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 Player::HandleInventoryMove(unsigned char *data)
|
|
{
|
|
if (ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendVaMessageC(17, "Cannot manipulate inventory while incapacitated");
|
|
return;
|
|
}
|
|
|
|
ObjectManager *om = GetObjectManager();
|
|
InvMove * Inventory = (InvMove *) data;
|
|
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 (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:
|
|
if (InvMo.FromSlot >= 0 && InvMo.FromSlot < 100) //sanity check, there a nvMo.ToInv of 0x01000000 which breaks this, not sure what it is.
|
|
{
|
|
Source = *ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].GetData();
|
|
}
|
|
|
|
if (InvMo.ToInv == 1) //cargo to cargo
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
//TODO: request to save inv slots
|
|
}
|
|
else if(InvMo.ToInv == 2) //equip from cargo
|
|
{
|
|
if (!m_Equip[InvMo.ToSlot].CanEquip(&Source))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//If we are moving ammo, they can stack if they are the same itemid
|
|
if (ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetItemTemplateID() == Source.ItemTemplateID)
|
|
{
|
|
Destination = *ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetData();
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
else
|
|
{
|
|
Destination = m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
else if(InvMo.ToInv == 3) //cargo to vault
|
|
{
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Destination = *PlayerIndex()->SecureInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
PlayerIndex()->SecureInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
|
|
SendAuxPlayer();
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
SaveVaultChange(InvMo.ToSlot);
|
|
}
|
|
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 <= (u32)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);
|
|
|
|
int sp_len = _snprintf(msg_buffer, 128, "You have gained %ld credits", Source.Price * InvMo.Num);
|
|
|
|
if (XP_earned > 0)
|
|
{
|
|
_snprintf(msg_buffer + sp_len, 128 - sp_len, " and %ld trade experience", XP_earned);
|
|
}
|
|
|
|
SendMessageString(msg_buffer, 3);
|
|
SendClientSound("coin.wav");
|
|
|
|
if (XP_earned > 0)
|
|
{
|
|
sprintf(msg_buffer, "Item(s) eligible for");
|
|
AwardTradeXP(msg_buffer, XP_earned);
|
|
}
|
|
|
|
PlayerIndex()->SetCredits(PlayerIndex()->GetCredits() + Source.Price * InvMo.Num);
|
|
SaveCreditLevel();
|
|
SendAuxPlayer();
|
|
SaveCreditLevel();
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
else if(InvMo.ToInv == 11) //spaceing item
|
|
{
|
|
Destination = Source;
|
|
Destination.StackCount -= InvMo.Num;
|
|
|
|
if (Destination.StackCount <= 0)
|
|
{
|
|
Destination = g_ItemBaseMgr->EmptyItem;
|
|
}
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
// Result box in Manufacturing
|
|
else if(InvMo.ToInv == 12 && (ManuIndex()->GetMode() == 2 || ManuIndex()->GetMode() == 3))
|
|
{
|
|
Destination = *ManuIndex()->Target.Item[0].GetData();
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
ManuIndex()->Target.Item[0].SetData(&Source);
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
// Control Interface box in Manufacturing
|
|
else if(InvMo.ToInv == 14 && ManuIndex()->GetMode() != 4)
|
|
{
|
|
Destination = *ManuIndex()->Override.Item[0].GetData();
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
ManuIndex()->Override.Item[0].SetData(&Source);
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
else if(InvMo.ToInv == 16) //cargo to trade
|
|
{
|
|
Destination = *ShipIndex()->Inventory.TradeInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (m_TradeID == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Player * targetp;
|
|
targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
targetp->SendItemBase(Source.ItemTemplateID);
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip();
|
|
ShipIndex()->Inventory.TradeInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
SendAuxShip(targetp);
|
|
targetp->TradeAction(0,6);
|
|
|
|
SaveInventoryChange(InvMo.FromSlot);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// From Equip Inventory
|
|
case 2:
|
|
Source = *ShipIndex()->Inventory.EquipInv.EquipItem[InvMo.FromSlot].GetItemData();
|
|
|
|
if (InvMo.ToInv == 1) //unequip item
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (!m_Equip[InvMo.FromSlot].CanEquip(&Destination))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Source = m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
SendAuxShip();
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
}
|
|
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 = *ShipIndex()->Inventory.EquipInv.EquipItem[InvMo.ToSlot].GetItemData();
|
|
|
|
//Moving two devices, just exchange them
|
|
if (InvMo.FromSlot > 8 || InvMo.ToSlot > 8)
|
|
{
|
|
Source = m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
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
|
|
else if (ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetItemTemplateID() != -2 ||
|
|
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 = *ShipIndex()->Inventory.AmmoInv.Item[InvMo.FromSlot].GetData();
|
|
Destination = *ShipIndex()->Inventory.AmmoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If neither have ammo, just swap them normally
|
|
Source = m_Equip[InvMo.FromSlot].Equip(&Destination);
|
|
m_Equip[InvMo.ToSlot].Equip(&Source);
|
|
}
|
|
|
|
SendAuxShip();
|
|
}
|
|
break;
|
|
|
|
// From Vault Inventory
|
|
case 3:
|
|
Source = *PlayerIndex()->SecureInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if(InvMo.ToInv == 11 || InvMo.ToSlot == -1) //destroy item
|
|
{
|
|
Destination = Source;
|
|
Destination.StackCount -= InvMo.Num;
|
|
|
|
if (Destination.StackCount <= 0)
|
|
{
|
|
Destination = g_ItemBaseMgr->EmptyItem;
|
|
}
|
|
|
|
PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxPlayer();
|
|
SaveVaultChange(InvMo.FromSlot);
|
|
}
|
|
else if (InvMo.ToInv == 1) //move from vault to cargo
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
|
|
SendAuxShip();
|
|
SendAuxPlayer();
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
SaveVaultChange(InvMo.FromSlot);
|
|
}
|
|
else if(InvMo.ToInv == 3) //vault to vault
|
|
{
|
|
Destination = *PlayerIndex()->SecureInv.Item[InvMo.ToSlot].GetData();
|
|
CheckStack(InvMo.Num, &Source, &Destination);
|
|
|
|
PlayerIndex()->SecureInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
PlayerIndex()->SecureInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxPlayer();
|
|
SaveVaultChange(InvMo.ToSlot);
|
|
SaveVaultChange(InvMo.FromSlot);
|
|
}
|
|
|
|
break;
|
|
|
|
// From Vendor Inventory
|
|
case 4:
|
|
if (InvMo.FromSlot >= 0 && InvMo.FromSlot < 100) //sanity check, there a nvMo.ToInv of 0x06000000 which breaks this, not sure what it is.
|
|
{
|
|
Source = *PlayerIndex()->VendorInv.Item[InvMo.FromSlot].GetData();
|
|
}
|
|
|
|
if (InvMo.ToInv == 1) //buy item
|
|
{
|
|
u64 Cost = Source.Price * InvMo.Num;
|
|
if (PlayerIndex()->GetCredits() < Cost)
|
|
{
|
|
SendVaMessage("Insufficient credits!");
|
|
return;
|
|
}
|
|
|
|
PlayerIndex()->SetCredits(PlayerIndex()->GetCredits() - Cost);
|
|
SaveCreditLevel();
|
|
|
|
//take losses on resales to vendors
|
|
Cost /= 4;
|
|
|
|
Source.StackCount = InvMo.Num; // Trade this many items
|
|
|
|
CargoAddItem(&Source);
|
|
SendAuxPlayer();
|
|
SendAuxShip();
|
|
}
|
|
break;
|
|
|
|
// From Loot Window
|
|
case 6:
|
|
{
|
|
Object *obj = 0;
|
|
if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_HUSK:
|
|
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", ShipIndex()->GetTargetGameID());
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Manufacturing Target
|
|
case 12:
|
|
if (InvMo.ToInv == 1 && (ManuIndex()->GetMode() == 2 || ManuIndex()->GetMode() == 3))
|
|
{
|
|
Source = *ManuIndex()->Target.Item[0].GetData();
|
|
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
CargoAddItem(&Source);
|
|
ManuIndex()->Target.Item[0].Empty();
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
}
|
|
else if (InvMo.ToInv == 1)
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
ManuIndex()->Target.Item[0].SetData(&Destination);
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Manufacturing Override
|
|
case 14:
|
|
if (InvMo.ToInv == 1 && ManuIndex()->GetMode() != 4)
|
|
{
|
|
Source = *ManuIndex()->Override.Item[0].GetData();
|
|
|
|
if (InvMo.ToSlot == -1)
|
|
{
|
|
CargoAddItem(&Source);
|
|
ManuIndex()->Override.Item[0].Empty();
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
}
|
|
else if (InvMo.ToInv == 1)
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
ManuIndex()->Override.Item[0].SetData(&Destination);
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
SendAuxShip();
|
|
SendAuxManu();
|
|
}
|
|
}
|
|
break;
|
|
|
|
// From Trade Window
|
|
case 16:
|
|
|
|
Source = *ShipIndex()->Inventory.TradeInv.Item[InvMo.FromSlot].GetData();
|
|
|
|
if (InvMo.ToInv == 1 && InvMo.ToSlot > 0) //back to inventory
|
|
{
|
|
Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData();
|
|
|
|
if (m_TradeID == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Player * targetp;
|
|
targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
targetp->SendItemBase(Source.ItemTemplateID);
|
|
ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].SetData(&Source);
|
|
SaveInventoryChange(InvMo.ToSlot);
|
|
SendAuxShip();
|
|
ShipIndex()->Inventory.TradeInv.Item[InvMo.FromSlot].SetData(&Destination);
|
|
SendAuxShip(targetp);
|
|
targetp->TradeAction(0,6);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
// From Mining Window
|
|
case 18:
|
|
{
|
|
Object *obj = 0;
|
|
if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_HUSK:
|
|
LootItem(InvMo.FromSlot);
|
|
break;
|
|
|
|
case OT_HULK:
|
|
case OT_RESOURCE:
|
|
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", 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);
|
|
|
|
SendVaMessage("UNRECOGNISED INVENTORY MOVE!\nPlease submit a bug report\n");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void Player::HandleItemState(unsigned char *data)
|
|
{
|
|
ItemState * Data = (ItemState *) data;
|
|
|
|
if (Data->Inventory == 2)
|
|
{
|
|
long ItemState = ShipIndex()->Inventory.EquipInv.EquipItem[Data->ItemNum].GetItemState();
|
|
|
|
if (Data->Enable == 1)
|
|
{
|
|
ItemState |= Data->BitMask;
|
|
}
|
|
else
|
|
{
|
|
ItemState &= ~Data->BitMask;
|
|
}
|
|
|
|
ShipIndex()->Inventory.EquipInv.EquipItem[Data->ItemNum].SetItemState(ItemState);
|
|
SendAuxShip();
|
|
}
|
|
else
|
|
{
|
|
LogMessage("UNRECOGNISED ITEM STATE:\n");
|
|
DumpBuffer(data, sizeof(ItemState));
|
|
|
|
SendVaMessage("UNRECOGNISED ITEM STATE!\nPlease submit a bug report\n");
|
|
}
|
|
}
|
|
|
|
void Player::HandleRequestTarget(unsigned char *data)
|
|
{
|
|
RequestTarget * request = (RequestTarget *) data;
|
|
ObjectManager *obj_manager = GetObjectManager();
|
|
Object *obj = (0);
|
|
|
|
if (obj_manager)
|
|
{
|
|
obj = obj_manager->GetObjectFromID(request->TargetID);
|
|
}
|
|
|
|
//LogMessage("Received RequestTarget packet\n");
|
|
|
|
if (m_ProspectWindow == true)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
|
|
SendSetTarget(request->TargetID, -1);
|
|
|
|
ShipIndex()->SetTargetGameID(request->TargetID);
|
|
|
|
|
|
// TB to David: Please tidy up the braces so they match the rest of the N7 source code.
|
|
// and fix typos, "Impossible"
|
|
|
|
if (obj && obj->ObjectType() == OT_MOB) {
|
|
int Lvl = obj->Level();
|
|
char Threat[40];
|
|
sprintf(Threat, "Level %d", Lvl);
|
|
ShipIndex()->SetTargetThreat(Threat);
|
|
//ShipIndex()->SetTargetThreatLevel(Lvl); // If Player Use this
|
|
|
|
} else if (obj && obj->ObjectType() == OT_PLAYER) {
|
|
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(request->TargetID);
|
|
|
|
if (p)
|
|
{
|
|
int LvlDif = p->CombatLevel() - CombatLevel();
|
|
char Threat[40];
|
|
|
|
if (LvlDif >= 8)
|
|
{
|
|
sprintf(Threat, "Impossible");
|
|
} else if (LvlDif >= 5)
|
|
{
|
|
sprintf(Threat, "Very Hard");
|
|
} else if (LvlDif >= 2)
|
|
{
|
|
sprintf(Threat, "Hard");
|
|
} else if (LvlDif >= -1)
|
|
{
|
|
sprintf(Threat, "Even");
|
|
} else if (LvlDif >= -4)
|
|
{
|
|
sprintf(Threat, "Easy");
|
|
} else if (LvlDif >= -7)
|
|
{
|
|
sprintf(Threat, "Very Easy");
|
|
} else {
|
|
sprintf(Threat, "Pathetic");
|
|
}
|
|
|
|
ShipIndex()->SetTargetThreat(Threat);
|
|
}
|
|
} else {
|
|
ShipIndex()->SetTargetThreatLevel(0);
|
|
ShipIndex()->SetTargetThreat("");
|
|
}
|
|
SendAuxShip();
|
|
BlankVerbs();
|
|
|
|
if (obj)
|
|
{
|
|
obj->OnTargeted(this);
|
|
}
|
|
}
|
|
|
|
void Player::HandleRequestTargetsTarget(unsigned char *data)
|
|
{
|
|
RequestTarget * request = (RequestTarget *) data;
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(request->TargetID);
|
|
|
|
if (p)
|
|
{
|
|
*((int *) &data[4]) = p->ShipIndex()->GetTargetGameID();
|
|
HandleRequestTarget(data);
|
|
}
|
|
else
|
|
{
|
|
SendSetTarget(0, -1);
|
|
ShipIndex()->SetTargetGameID(-1);
|
|
SendAuxShip();
|
|
}
|
|
}
|
|
|
|
bool Player::CheckResourceLock(long object_id)
|
|
{
|
|
Player * player = 0;
|
|
ObjectManager *om = GetObjectManager();
|
|
Object *obj = (0);
|
|
if (om) obj = om->GetObjectFromID(object_id);
|
|
|
|
if (obj)
|
|
{
|
|
player = obj->CheckResourceLock();
|
|
}
|
|
|
|
if (player && player != this)
|
|
{
|
|
SendVaMessage("%s is being mined by %s", obj->Name(), player->Name());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
long Player::CurrentResourceTarget()
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
return (ShipIndex()->GetTargetGameID());
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void Player::HandleVerbRequest(unsigned char *data)
|
|
{
|
|
//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 *) data;
|
|
|
|
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 == GameID() && pkt->Action == 1)
|
|
{
|
|
UpdateVerbs(true);
|
|
}
|
|
}
|
|
|
|
void Player::OpenInterface(long UIChange, long UIType)
|
|
{
|
|
SetInterface set_interface;
|
|
set_interface.UIChange = UIChange;
|
|
set_interface.UIType = UIType;
|
|
|
|
//LogMessage("Sending SetInterface packet\n");
|
|
SendOpcode(ENB_OPCODE_0066_OPEN_INTERFACE, (unsigned char *) &set_interface, sizeof(set_interface));
|
|
}
|
|
|
|
void Player::CloseInterfaceIfTargetted(long target_id)
|
|
{
|
|
if (ShipIndex()->GetTargetGameID() == target_id)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
}
|
|
|
|
void Player::CloseInterfaceIfOpen()
|
|
{
|
|
if (m_ProspectWindow)
|
|
{
|
|
m_ProspectWindow = false;
|
|
OpenInterface(1,0);
|
|
}
|
|
}
|
|
|
|
void Player::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;
|
|
|
|
SendOpcode(ENB_OPCODE_008B_ATTACKER_UPDATES, attacker_data, sizeof(attacker_data));
|
|
}
|
|
void Player::SendChangeBasset(ChangeBaseAsset *NewAsset)
|
|
{
|
|
SendOpcode(ENB_OPCODE_0026_CHANGE_BASE_ASSET, (unsigned char*) NewAsset, sizeof(ChangeBaseAsset));
|
|
}
|
|
|
|
void Player::SendObjectLinkedEffectRL(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 = GameID();
|
|
OBTOBE.TargetID = UID;
|
|
OBTOBE.EffectDescID = effectDID;
|
|
OBTOBE.Message = 0;
|
|
OBTOBE.EffectID = effectID;
|
|
OBTOBE.Duration = short(effect_time);
|
|
OBTOBE.TimeStamp = GetNet7TickCount();
|
|
|
|
SendObjectToObjectEffectRL(&OBTOBE);
|
|
}
|
|
|
|
void Player::CheckObjectRanges()
|
|
{
|
|
ObjectManager *om = GetObjectManager();
|
|
if (!m_DebugPlayer && om)
|
|
{
|
|
om->DisplayDynamicObjects(this);
|
|
}
|
|
|
|
CheckArrivalTriggers();
|
|
}
|
|
|
|
void Player::SendSetTarget(int game_id, int target_id)
|
|
{
|
|
SetTarget set_target;
|
|
set_target.GameID = game_id;
|
|
set_target.TargetID = target_id;
|
|
|
|
SendOpcode(ENB_OPCODE_0019_SET_TARGET, (unsigned char *) &set_target, sizeof(set_target));
|
|
}
|
|
|
|
void Player::SendRemoveEffect(int target_id)
|
|
{
|
|
SendOpcode(ENB_OPCODE_000F_REMOVE_EFFECT, (unsigned char *) &target_id, sizeof(int));
|
|
}
|
|
|
|
void Player::TradeAction(long GameID, int Action)
|
|
{
|
|
unsigned char buffer[5];
|
|
|
|
*((long *) &buffer[0]) = GameID;
|
|
*((char *) &buffer[4]) = (char) Action;
|
|
|
|
SendOpcode(ENB_OPCODE_001F_TRADE, buffer, 5);
|
|
}
|
|
|
|
void Player::SendConfirmation(char * msg, int PlayerID, int Ability)
|
|
{
|
|
unsigned char buffer[2000];
|
|
int index = 0;
|
|
|
|
// Save this data so we can call back
|
|
m_Confirmation = 2;
|
|
m_Confirmation_PlayerID = PlayerID;
|
|
m_Confirmation_Ability = Ability;
|
|
|
|
*((short *) &buffer[index]) = strlen(msg) + 1; index += 2;
|
|
*((char *) &buffer[index]) = (char) 0x01; index++;
|
|
memcpy(&buffer[index], msg, strlen(msg) + 1); index += (strlen(msg) + 1);
|
|
|
|
SendOpcode(ENB_OPCODE_001E_GROUP, buffer, index);
|
|
}
|
|
|
|
void Player::HandleAction(unsigned char *data)
|
|
{
|
|
ActionPacket * myAction = (ActionPacket *) data;
|
|
char message[128];
|
|
ObjectManager *om = GetObjectManager();
|
|
Object *obj = (0);
|
|
if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
LogDebug("Action - ID: 0x%x, Action: %d, Target: %d, OptVar: %d\n",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
|
|
int x;
|
|
|
|
switch (myAction->Action)
|
|
{
|
|
case 1: //tractor
|
|
if (ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to tractor while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj)
|
|
{
|
|
//shouldnt targeted ID be myAction->target??
|
|
//you would think that, but for some reason HULK action doesn't send the target ID...
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_FLOATING_ORE:
|
|
LootItem(0);
|
|
break;
|
|
|
|
case OT_HUSK:
|
|
if (m_ProspectWindow == false && CheckResourceLock(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)
|
|
{
|
|
SendVaMessage("DOCKING FAULT: Station needs docking sector to be set in DASE. Inform content devs.");
|
|
break;
|
|
}
|
|
m_SectorMgr->SectorServerHandoff(this, destination);
|
|
break;
|
|
}
|
|
case 8: //land
|
|
if (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();
|
|
|
|
TerminateWarp();
|
|
m_SectorMgr->SectorServerHandoff(this, obj->Destination());
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 9: //fire all weapons
|
|
{
|
|
// if you are incapacited you cant equip items
|
|
if (ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to fire weapons while incapacitated.", 11);
|
|
return;
|
|
}
|
|
FireAllWeapons();
|
|
break;
|
|
}
|
|
case 10: //invite target to group
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.GroupInvite(GroupID(),GameID(),myAction->Target);
|
|
break;
|
|
}
|
|
case 11: //accept group invitation
|
|
{
|
|
// See if we have a conformation up insted of group
|
|
if (m_Confirmation == 2)
|
|
{
|
|
Player * p = g_ServerMgr->m_PlayerMgr.GetPlayer(m_Confirmation_PlayerID);
|
|
|
|
if (p && p->m_AbilityList[m_Confirmation_Ability])
|
|
{
|
|
// Call back and give a responce
|
|
p->m_AbilityList[m_Confirmation_Ability]->Confirmation(true);
|
|
}
|
|
|
|
// reset data
|
|
m_Confirmation = 0;
|
|
}
|
|
else
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.AcceptGroupInvite(GroupID(),GameID());
|
|
m_Confirmation = 0;
|
|
}
|
|
break;
|
|
}
|
|
case 12: //decline group invitation
|
|
{
|
|
// See if we have a conformation up insted of group
|
|
if (m_Confirmation == 2)
|
|
{
|
|
Player * p = g_ServerMgr->m_PlayerMgr.GetPlayer(m_Confirmation_PlayerID);
|
|
|
|
if (p && p->m_AbilityList[m_Confirmation_Ability])
|
|
{
|
|
// Call back and give a responce
|
|
p->m_AbilityList[m_Confirmation_Ability]->Confirmation(false);
|
|
}
|
|
|
|
// reset data
|
|
m_Confirmation = 0;
|
|
}
|
|
else
|
|
{
|
|
m_Confirmation = 0;
|
|
g_ServerMgr->m_PlayerMgr.RejectGroupInvite(GroupID(), GameID());
|
|
}
|
|
break;
|
|
}
|
|
case 13: //disban group
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.DisbanGroup(GroupID(), GameID());
|
|
break;
|
|
}
|
|
case 14: //leave group
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.LeaveGroup(GroupID(), GameID());
|
|
break;
|
|
}
|
|
case 15: //kick target from group
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.KickFromGroup(GroupID(), GameID(), myAction->Target);
|
|
break;
|
|
}
|
|
case 17: //mine
|
|
{
|
|
if (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 (ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to gate while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj != 0 && obj->ObjectType() == OT_STARGATE)
|
|
{
|
|
if (this->GroupID() != -1)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.BreakFormation(GameID());
|
|
g_ServerMgr->m_PlayerMgr.LeaveFormation(GameID());
|
|
}
|
|
TerminateWarp();
|
|
SendClientSound("1512_00_032Se.mp3",0,0);
|
|
m_SectorMgr->GateActivate(this, myAction->Target);
|
|
}
|
|
break;
|
|
}
|
|
case 19: //finish gate sequence
|
|
{
|
|
m_SectorMgr->SectorServerHandoff(this, StargateDestination());
|
|
}
|
|
break;
|
|
|
|
//TODO: Remove confirm if trade changes
|
|
case 20: //trade
|
|
{
|
|
Player * targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(myAction->Target);
|
|
if (targetp)
|
|
{
|
|
if (targetp->m_TradeID != -1)
|
|
{
|
|
SendVaMessage("That player is already trading with someone!");
|
|
}
|
|
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
SendAuxShip(targetp);
|
|
targetp->SendAuxShip(this);
|
|
|
|
// TESTING
|
|
if (!Active() && myAction->Target != GameID())
|
|
{
|
|
SendCreate(targetp->GameID(), 1, 0x4B06, CREATE_SHIP, 0, 0, 0);
|
|
targetp->SendCreate(GameID(), 1, 0x4B06, CREATE_SHIP, 0, 0, 0);
|
|
}
|
|
// -------
|
|
|
|
TradeAction(myAction->Target,0); // Opens a trade window
|
|
targetp->TradeAction(myAction->GameID, 0); // Open trade window for other player
|
|
m_TradeID = myAction->Target; // Set player tradeing with
|
|
m_TradeConfirm = 0;
|
|
targetp->m_TradeID = myAction->GameID;
|
|
targetp->m_TradeConfirm = 0;
|
|
}
|
|
}
|
|
break;
|
|
case 21: //confirm trade
|
|
{
|
|
Player * targetp;
|
|
targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(m_TradeID);
|
|
m_TradeConfirm = 1;
|
|
TradeAction(0,3);
|
|
|
|
if (targetp)
|
|
{
|
|
targetp->TradeAction(0,5);
|
|
}
|
|
|
|
if (targetp && targetp->m_TradeConfirm == 1)
|
|
{
|
|
LogMessage("Trade comfirned for players %x and %x\n",myAction->GameID,myAction->Target);
|
|
|
|
//close windows and reset tradeIds
|
|
TradeAction(m_TradeID,2);
|
|
targetp->TradeAction(myAction->GameID, 2);
|
|
m_TradeID = -1;
|
|
targetp->m_TradeID = -1;
|
|
|
|
//add and remove credits
|
|
PlayerIndex()->SetCredits(PlayerIndex()->GetCredits() + targetp->ShipIndex()->GetTradeMoney() - ShipIndex()->GetTradeMoney());
|
|
SaveCreditLevel();
|
|
SendAuxPlayer();
|
|
targetp->PlayerIndex()->SetCredits(targetp->PlayerIndex()->GetCredits() + ShipIndex()->GetTradeMoney() - targetp->ShipIndex()->GetTradeMoney());
|
|
targetp->SaveCreditLevel();
|
|
targetp->SendAuxPlayer();
|
|
|
|
//Add other player's items
|
|
for(x=0;x<6;x++)
|
|
{
|
|
CargoAddItem(targetp->ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
SendAuxShip();
|
|
|
|
//add items to other player
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->CargoAddItem(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();
|
|
ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
SendAuxShip(targetp);
|
|
targetp->SendAuxShip(this);
|
|
|
|
// Reset money
|
|
targetp->ShipIndex()->SetTradeMoney(0);
|
|
ShipIndex()->SetTradeMoney(0);
|
|
|
|
|
|
// TESTING
|
|
if (!Active() && myAction->Target != GameID()) // if we are in a station use this
|
|
{
|
|
RemoveObject(targetp->GameID());
|
|
targetp->RemoveObject(GameID());
|
|
}
|
|
// ----
|
|
}
|
|
}
|
|
break;
|
|
case 22: //cancel trade
|
|
{
|
|
CancelTrade();
|
|
}
|
|
break;
|
|
case 23: //keep trading???
|
|
{
|
|
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 = g_ServerMgr->m_PlayerMgr.GetPlayer(m_TradeID);
|
|
if (targetp)
|
|
{
|
|
ShipIndex()->SetTradeMoney(myAction->OptionalVar);
|
|
SendAuxShip(targetp);
|
|
SendAuxShip();
|
|
TradeAction(m_TradeID,4);
|
|
targetp->TradeAction(m_TradeID,4);
|
|
}
|
|
}
|
|
break;
|
|
case 25: //register
|
|
if (obj)
|
|
{
|
|
//Starbase Registration
|
|
if (obj->ObjectType() == OT_STATION && m_RegisteredSectorID != obj->Destination())
|
|
{
|
|
SendClientSound("Reg_OK",0,0);
|
|
_snprintf(message, 128, "%s control: Registration Confirmed.", obj->Name());
|
|
SendMessageString(message,5);
|
|
|
|
m_RegisteredSectorID = obj->Destination();
|
|
|
|
SaveRegisteredStarbase();
|
|
|
|
PlayerIndex()->SetRegistrationStarbase(obj->Name());
|
|
PlayerIndex()->SetRegistrationStarbaseSector(PlayerIndex()->GetSectorName());
|
|
}
|
|
break;
|
|
}
|
|
case 26: // Jump Start
|
|
if (!obj)
|
|
{
|
|
SendVaMessage("Invalid JS target! SUBMIT BUG REPORT!");
|
|
return;
|
|
}
|
|
|
|
if (obj->ObjectType() == OT_PLAYER)
|
|
{
|
|
// Make sure we can use the ability
|
|
if (m_AbilityList[JUMPSTART]->CanUse(obj->GameID(), JUMPSTART, SKILL_JUMPSTART))
|
|
{
|
|
// Execute the ability
|
|
m_AbilityList[JUMPSTART]->Use(obj->GameID());
|
|
}
|
|
}
|
|
break;
|
|
case 28: //dock
|
|
// if you are incapacited you cant equip items
|
|
if (ShipIndex()->GetIsIncapacitated())
|
|
{
|
|
SendMessageString("Unable to dock while incapacitated.", 11);
|
|
return;
|
|
}
|
|
if (obj)
|
|
{
|
|
if (obj->ObjectType() == OT_STATION)
|
|
{
|
|
if (this->GroupID() != -1)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.BreakFormation(GameID());
|
|
g_ServerMgr->m_PlayerMgr.LeaveFormation(GameID());
|
|
}
|
|
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();
|
|
SendEffectRL(obj->GameID(), 0, 10007, UID, GetNet7TickCount(), 3000);
|
|
//by default when you scan something you cause a mission advance
|
|
MissionObjectScan(obj);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
LogMessage("UNRECOGNIZED ACTION! ID: %d, Action: %d, Target: %d, OptVar: %d\n",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
SendVaMessage("UNRECOGNIZED ACTION! SUBMIT BUG REPORT!");
|
|
SendVaMessage("Action ID: %d, Action: %d, Target: %d, OptVar: %d",myAction->GameID, myAction->Action, myAction->Target, myAction->OptionalVar);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Player::CancelTrade()
|
|
{
|
|
Player * targetp;
|
|
targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(m_TradeID);
|
|
int x;
|
|
|
|
if (targetp)
|
|
{
|
|
TradeAction(m_TradeID,1); // Closes a trade window
|
|
targetp->TradeAction(GameID(), 1); // Closes trade window for other player
|
|
m_TradeID = -1; // No longer Tradeing
|
|
targetp->m_TradeID = -1;
|
|
|
|
//return player's items
|
|
for(x=0;x<6;x++)
|
|
{
|
|
CargoAddItem(ShipIndex()->Inventory.TradeInv.Item[x].GetData());
|
|
}
|
|
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", GameID(), m_TradeID);
|
|
for(x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
SendAuxShip(targetp);
|
|
targetp->SendAuxShip(this);
|
|
|
|
targetp->m_TradeConfirm = 0;
|
|
m_TradeConfirm = 0;
|
|
|
|
// Reset money
|
|
targetp->ShipIndex()->SetTradeMoney(0);
|
|
ShipIndex()->SetTradeMoney(0);
|
|
|
|
// TESTING
|
|
if (!Active() && m_TradeID != GameID())
|
|
{
|
|
RemoveObject(targetp->GameID());
|
|
targetp->RemoveObject(GameID());
|
|
}
|
|
// ----
|
|
}
|
|
}
|
|
|
|
void Player::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();
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
}
|
|
}
|
|
|
|
/*
|
|
void Player::SendResourceContentsAUXForHulk(Object *obj)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (obj)
|
|
{
|
|
contents_already_sent = obj->GetIndex(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();
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, aux_data, sizeof(aux_data));
|
|
obj->SetIndex(ResourceSendList());
|
|
}
|
|
}
|
|
}*/
|
|
|
|
//TODO: make this part of AUX handler.
|
|
void Player::SendResourceContentsAUX(Object *obj)
|
|
{
|
|
bool contents_already_sent;
|
|
|
|
if (obj)
|
|
{
|
|
contents_already_sent = obj->GetIndex(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);
|
|
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;
|
|
|
|
SendOpcode(ENB_OPCODE_001B_AUX_DATA, packet, index);
|
|
obj->SetIndex(ResourceSendList());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::SendCameraControl(long Message, long GameID)
|
|
{
|
|
CameraControl data;
|
|
data.Message = Message;
|
|
data.GameID = GameID;
|
|
|
|
//LogMessage("Sending CameraControl packet\n");
|
|
SendOpcode(ENB_OPCODE_0092_CAMERA_CONTROL, (unsigned char *) &data, sizeof(data));
|
|
}
|
|
|
|
bool Player::MatchOptWithParam (const 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
|
|
{
|
|
SendVaMessage("Missing arg for option %s", option);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Player::HandleEquipUse(unsigned char *data)
|
|
{
|
|
EquipUse *myUse = (EquipUse *) data;
|
|
|
|
m_Equip[myUse->InvSlot].ManualActivate();
|
|
}
|
|
|
|
void Player::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);
|
|
|
|
SendOpcode(ENB_OPCODE_0064_CLIENT_DAMAGE, packet, index);
|
|
}
|
|
|
|
//what's this?
|
|
void Player::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;
|
|
|
|
SendOpcode(0x62, (unsigned char *) &Data, Index);
|
|
}
|
|
|
|
void Player::HandleClientChat(unsigned char *data)
|
|
{
|
|
ClientChat * chat = (ClientChat *) data;
|
|
const 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] != '/'))
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.ChatSendEveryone(chat->GameID, chat->String);
|
|
}
|
|
|
|
if ((chat->Type == 1) && this)
|
|
{
|
|
if (GroupID() != -1)
|
|
g_ServerMgr->m_PlayerMgr.GroupChat(GroupID(),Name(), chat->String);
|
|
else
|
|
SendVaMessage("Error: You are not in a group!");
|
|
}
|
|
|
|
if (chat->String[0] == '/')
|
|
{
|
|
HandleSlashCommands(chat->String);
|
|
}
|
|
}
|
|
|
|
|
|
void Player::HandleSlashCommands(char *Msg)
|
|
{
|
|
bool success = false;
|
|
bool msg_sent = false;
|
|
|
|
// 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 (Msg[0] == '/' && Msg[1] == '/' && Msg[2] != 0 && AdminLevel() >= 50)
|
|
{
|
|
char *param;
|
|
char *pch = (char*)_alloca(strlen(&Msg[2]) + 1);//copy to stack to avoid heap fragment
|
|
strcpy(pch, &Msg[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)
|
|
{
|
|
SendVaMessage("Syntax: //adduser <username> <password> <access>");
|
|
return;
|
|
}
|
|
|
|
if (g_AccountMgr->AddUser(Username, Password, Access))
|
|
{
|
|
SendVaMessage("Account %s / %s / %s Created", Username, Password, Access);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Account creation failed!");
|
|
}
|
|
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
{
|
|
if (strcmp(pch, "rstations") == 0)
|
|
{
|
|
// Read in stations again
|
|
SendVaMessage("Reloading Stations...");
|
|
g_ServerMgr->m_StationMgr.LoadStations();
|
|
SendVaMessage("Station Reload Complete.");
|
|
if (PlayerIndex()->GetSectorNum() > 9999)
|
|
{
|
|
SendVaMessage("You must launch into space and re-dock for changes.");
|
|
}
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (strcmp(pch, "rsectors") == 0)
|
|
{
|
|
// Read in sectors again
|
|
long scan_range = ShipIndex()->CurrentStats.GetScanRange();
|
|
ShipIndex()->CurrentStats.SetScanRange(10); //set ship almost blind
|
|
CheckObjectRanges();
|
|
|
|
SendVaMessage("Reloading Sectors and mobs...");
|
|
g_ServerMgr->m_MOBList.LoadMOBContent();
|
|
g_ServerMgr->m_SectorContent.LoadSectorContent();
|
|
SendVaMessage("Sector Reload Complete.");
|
|
if (PlayerIndex()->GetSectorNum() < 9999)
|
|
{
|
|
SendVaMessage("You must change sectors to see changes to navs.");
|
|
}
|
|
|
|
ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
ResetRangeLists();
|
|
CheckObjectRanges();
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (strcmp(pch, "ritems") == 0)
|
|
{
|
|
SendVaMessage("Reloading Items...");
|
|
g_ServerMgr->m_ItemBaseMgr.Initialize();
|
|
SendVaMessage("Items Reloaded.");
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (strcmp(pch, "rmissions") == 0)
|
|
{
|
|
SendVaMessage("Reloading Missions...");
|
|
g_ServerMgr->m_Missions.LoadMissionContent();
|
|
SendVaMessage("Missions Reloaded.");
|
|
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)
|
|
{
|
|
SendVaMessage("Syntax: //setpassword <username> <password>");
|
|
return;
|
|
}
|
|
|
|
g_AccountMgr->ChangePassword(Username, Password);
|
|
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)
|
|
{
|
|
SendVaMessage("Player `%s` not found", param);
|
|
return;
|
|
}
|
|
|
|
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)
|
|
{
|
|
SendVaMessage("Syntax: //gmsetaccess <playername> <password>");
|
|
return;
|
|
}
|
|
|
|
Player * target = g_PlayerMgr->GetPlayer(Username);
|
|
if (!target)
|
|
{
|
|
SendVaMessage("Player `%s` not found", Username);
|
|
return;
|
|
}
|
|
|
|
long new_access = atoi(Access);
|
|
|
|
// Can't promote over your level
|
|
if (new_access > AdminLevel())
|
|
new_access = AdminLevel();
|
|
|
|
// Can't demote someone above your access
|
|
if (g_AccountMgr->GetAccountStatus(target->AccountUsername()) > AdminLevel())
|
|
{
|
|
SendVaMessage("Can't change access for player above your access level");
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
g_AccountMgr->SetAccountStatus(target->AccountUsername(), new_access);
|
|
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 = g_ServerMgr->m_PlayerMgr.GetPlayer(Username);
|
|
|
|
if (!TargetP)
|
|
{
|
|
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);
|
|
SendVaMessage("You have gave %s %d SkillPoints", Username, SkillPoints);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Syntax: //gmskillpoints <playername> <skillpoints>");
|
|
success = false;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("gmenableskills", pch, param, msg_sent))
|
|
{
|
|
char *PlayerName = strtok(param, " ");
|
|
|
|
if (!PlayerName)
|
|
{
|
|
SendVaMessage("Syntax: //gmenableskills <playername>");
|
|
msg_sent = true;
|
|
success = false;
|
|
}
|
|
else
|
|
{
|
|
Player * TargetP = g_ServerMgr->m_PlayerMgr.GetPlayer(PlayerName);
|
|
|
|
if (!TargetP)
|
|
{
|
|
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");
|
|
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 = g_ServerMgr->m_PlayerMgr.GetPlayer(Username);
|
|
|
|
if (!TargetP)
|
|
{
|
|
SendVaMessage("Player %s is not online", Username);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (TargetP->AdminLevel() <= 30)
|
|
{
|
|
SendVaMessage("Unable to use gmplayerlevel on BETA and below at the moment - reason: more low level testing needed.");
|
|
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);
|
|
SendVaMessage("Player %s leveled to %d", Username, Level);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Syntax: //gmplayerlevel <playername> <level 1-50>");
|
|
msg_sent = true;
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// This is for normal commands
|
|
if ((Msg[0] == '/') &&
|
|
(Msg[1] != 0) && (!msg_sent || !success))
|
|
{
|
|
char *param;
|
|
char *pch = (char*)_alloca(strlen(&Msg[1]) + 1);//copy to stack to avoid heap fragment
|
|
strcpy(pch, &Msg[1]);
|
|
int retval = 0;
|
|
switch(*pch)
|
|
{
|
|
case 'a':
|
|
{
|
|
if (strcmp(pch, "authlevel") == 0)
|
|
{
|
|
SendVaMessage("Authentication Level - Num: %d", AdminLevel());
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (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);
|
|
}
|
|
|
|
//ChangeMountBoneName(weapon_id, bone_id);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
if (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)
|
|
{
|
|
ChangeMountBoneName(weapon_id, cmd);
|
|
SendVaMessage("Change weapon id #%d to %s", weapon_id, cmd);
|
|
}
|
|
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
{
|
|
if (MatchOptWithParam("basset", pch, param, msg_sent))
|
|
{
|
|
success = HandleBassetRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
//BUFF for future reference
|
|
if (MatchOptWithParam("buff", pch, param, msg_sent))
|
|
{
|
|
Buff TestBuff;
|
|
memset(&TestBuff, 0, sizeof(Buff));
|
|
|
|
strcpy(TestBuff.BuffType, param);
|
|
TestBuff.ExpireTime = GetNet7TickCount() + 100000;
|
|
TestBuff.IsPermanent = false;
|
|
|
|
m_Buffs.AddBuff(&TestBuff);
|
|
SendVaMessage("Sending buff 0!\n");
|
|
msg_sent = true;
|
|
}
|
|
else if (AdminLevel() == 90 && MatchOptWithParam("baseitemlist", pch, param, msg_sent)) //one use only, remove once table created
|
|
{
|
|
success = HandleBaseItemListCreate();
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
case 'c':
|
|
{
|
|
if (MatchOptWithParam("ccamera", pch, param, msg_sent))
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
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))
|
|
{
|
|
g_ServerMgr->m_AccountMgr->ChangePassword(AccountUsername(), param);
|
|
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(AccountUsername(), "Tienbau")) //temp lockout for testing
|
|
{
|
|
SendVaMessage("Unable to create.");
|
|
}
|
|
else if (AdminLevel() >= 50) // GM to Admin (Beta testers tend to spam this with random numbers)
|
|
{
|
|
int FreeSlot = GetCargoSlotFromItemID(0, -1);;
|
|
|
|
if (FreeSlot == -1)
|
|
{
|
|
SendVaMessage("No free slots in inventory free up space");
|
|
}
|
|
else
|
|
{
|
|
_Item myItem = g_ItemBaseMgr->EmptyItem;
|
|
|
|
char *ItemIDs = strtok(param, " ");
|
|
char *NumberS;
|
|
char *QualityS;
|
|
int Number;
|
|
float Quality = 1;
|
|
|
|
if (ItemIDs)
|
|
{
|
|
NumberS = strtok(NULL, " ");
|
|
if (NumberS)
|
|
{
|
|
Number = atoi(NumberS);
|
|
|
|
QualityS = strtok(NULL, " ");
|
|
if (QualityS)
|
|
{
|
|
Quality = (float)atof(QualityS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Number = 1;
|
|
}
|
|
|
|
if (Quality > 2.0f) Quality = 2.0f;
|
|
|
|
myItem.ItemTemplateID = atoi(ItemIDs);
|
|
myItem.StackCount = Number;
|
|
myItem.Price = 200;
|
|
myItem.Quality = Quality;
|
|
myItem.Structure = 1;
|
|
strcpy(myItem.BuilderName, this->Name());
|
|
strcat(myItem.BuilderName, " GM/DEV");
|
|
|
|
if (CargoAddItem(&myItem) != -2)
|
|
{
|
|
SendAuxShip();
|
|
SendVaMessage("Item %d Created %d", atoi(ItemIDs), Number);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("No item exists with id %d", myItem.ItemTemplateID);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Number = 1;
|
|
SendVaMessage("/createitem used incorrectly.");
|
|
}
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("GM Only command.");
|
|
}
|
|
}
|
|
else if (MatchOptWithParam("createcredits", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
PlayerIndex()->SetCredits(PlayerIndex()->GetCredits() + _atoi64(param));
|
|
SaveCreditLevel();
|
|
SendAuxPlayer();
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("GM Only command.");
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
/*
|
|
else if (MatchOptWithParam("createmission", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
g_ServerMgr->m_Missions.givePlayerMission(this, atoi(param));
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("GM Only command.");
|
|
}
|
|
}
|
|
*/
|
|
else if (MatchOptWithParam("createmob", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 50) // GM -> admin
|
|
{
|
|
success = HandleMobCreateRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
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(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
Player *player = obj->CheckResourceLock();
|
|
if (player)
|
|
{
|
|
SendVaMessage("Currently being mined/looted by %s", player);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Not being looted.");
|
|
}
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "commit") == 0 && AdminLevel() >= 80)
|
|
{
|
|
success = HandleCommitRequest(ShipIndex()->GetTargetGameID());
|
|
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
|
|
&& 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);
|
|
char msg_buffer[128];
|
|
Object *obj = m_ObjectMgr->AddNewObject(OT_DECO);
|
|
obj->SetPosition(Position());
|
|
obj->SetBasset(basset);
|
|
obj->SetSignature(30000.0f);
|
|
obj->SetOrientation(0,0,0,0);
|
|
obj->SetScale(1.0f);
|
|
m_CurrentDecoObj = obj;
|
|
AssetData *asset = g_ServerMgr->AssetList()->GetAssetData(basset);
|
|
|
|
if (asset && asset->m_Name)
|
|
{
|
|
_snprintf(msg_buffer, 127, "%d:%s", basset, asset->m_Name);
|
|
SendPushMessage(msg_buffer, "MessageLine", 3000, 3);
|
|
}
|
|
|
|
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;
|
|
}
|
|
else if (strcmp(pch, "dockp") == 0)
|
|
{
|
|
success = true;
|
|
msg_sent = true;
|
|
DebugPlayerDock(true);
|
|
//g_ServerMgr->m_PlayerMgr.SendPlayerWithoutConnection(GameID());
|
|
}
|
|
break;
|
|
case 'e' :
|
|
{
|
|
if (AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
|
|
if (strcmp(pch, "enableskills") == 0)
|
|
{
|
|
u32 Availability[4] = {4,0,0,1};
|
|
for (int i=0;i<64;i++)
|
|
{
|
|
if (PlayerIndex()->RPGInfo.Skills.Skill[i].GetAvailability()[0] == 3)
|
|
{
|
|
PlayerIndex()->RPGInfo.Skills.Skill[i].SetAvailability(Availability);
|
|
}
|
|
SendAuxPlayer();
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
|
|
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 = GameID();
|
|
WarpEffect.Duration = Length;
|
|
WarpEffect.TimeStamp = GetNet7TickCount();
|
|
|
|
m_Effects.AddEffect(&WarpEffect);
|
|
|
|
//SendObjectEffectRL(&WarpEffect);
|
|
|
|
SendVaMessage("Send Effect %d Disc: %d for %dms", WarpEffect.EffectID, EffectDID, Length);
|
|
}
|
|
else
|
|
{
|
|
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 = 1.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 = (float)atof(cmd);
|
|
bitmask += 0x40;
|
|
cmd = strtok(NULL, " ");
|
|
if (cmd)
|
|
{
|
|
speedup = (float)atof(cmd);
|
|
bitmask += 0x100;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Length = 4000;
|
|
}
|
|
|
|
if (count == 1)
|
|
{
|
|
ObjectToObjectEffect OBTOBE;
|
|
memset(&OBTOBE, 0, sizeof(ObjectToObjectEffect));
|
|
|
|
OBTOBE.Bitmask = bitmask;
|
|
OBTOBE.GameID = GameID();
|
|
OBTOBE.TargetID = 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;
|
|
|
|
SendObjectToObjectEffectRL(&OBTOBE);
|
|
SendVaMessage("Send Effect %d Disc: %d to Object", OBTOBE.EffectID, EffectDID);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/effecto <effect_desc_id> <length>");
|
|
}
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("effects", pch, param, msg_sent))
|
|
{
|
|
int EffectID = atoi(strtok(param, " "));
|
|
|
|
m_Effects.RemoveEffect(EffectID);
|
|
|
|
SendVaMessage("Stopping Effect %d", EffectID);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("exposedecos", pch, param, msg_sent))
|
|
{
|
|
success = true;
|
|
msg_sent = true;
|
|
|
|
if (GetObjectManager())
|
|
{
|
|
bool selection = false;
|
|
if (strcmp(param, "on") == 0) selection = true;
|
|
|
|
if (selection)
|
|
{
|
|
if (!ObjectIsMoving())
|
|
{
|
|
SendVaMessage("Nearby decos should now be clickable.");
|
|
m_ExposeDecos = true;
|
|
if (m_SectorMgr->GetSectorType() == 0)
|
|
{
|
|
RemoveFromAllSectorRangeLists();
|
|
m_SectorMgr->SectorServerHandoff(this, PlayerIndex()->GetSectorNum());
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to auto-wormhole you, please leave sector and return to expose decos.");
|
|
}
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("You should be stationary when using /exposedecos.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ExposeDecos = false;
|
|
SendVaMessage("Decos no longer exposed - gate out of system to return to normal");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'f':
|
|
if (AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
if (MatchOptWithParam("form", pch, param, msg_sent) && AdminLevel() >= 50)
|
|
{
|
|
SendVaMessage("Forming up target!");
|
|
SendFormationPositionalUpdate(this->GameID(), ShipIndex()->GetTargetGameID(), 100, 100, 100);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
if (strcmp(pch, "flushinv") == 0)
|
|
{
|
|
// Flush invtory clean!
|
|
for(u32 Slot=0;Slot<ShipIndex()->Inventory.GetCargoSpace();Slot++)
|
|
{
|
|
ShipIndex()->Inventory.CargoInv.Item[Slot].Empty();
|
|
}
|
|
|
|
SendAuxShip();
|
|
SendVaMessage("Your inventory is now flushed!");
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (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 = g_ServerMgr->m_PlayerMgr.GetPlayer(param);
|
|
if (target)
|
|
{
|
|
SendVaMessage("Player found! Name: `%s` GameID: %x Account: `%s`",target->Name(), target->GameID(),target->AccountUsername());
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Player `%s` not found!", param);
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (strcmp(pch, "face") == 0)
|
|
{
|
|
success = HandleFaceRequest(ShipIndex()->GetTargetGameID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "faceme") == 0)
|
|
{
|
|
success = HandleFaceMeRequest(ShipIndex()->GetTargetGameID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "fgps") == 0)
|
|
{
|
|
ProcessConfirmedActionOffer();
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
|
|
/*TODO:
|
|
SendVaMessage("/faddore <ore itemID from database> - adds ore choice to field");
|
|
SendVaMessage("/fremoveore <ore itemID from database> - removes ore choice from field");*/
|
|
|
|
if (AdminLevel() >= 80)
|
|
{
|
|
if (MatchOptWithParam("fradius", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 1);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("ftype", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 2);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("flevel", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 3);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("fcount", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 4);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("faddasteroidtpe", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 5);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("faddore", pch, param, msg_sent))
|
|
{
|
|
success = HandleChangeFieldRequest(param, 6);
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'g':
|
|
if (MatchOptWithParam("gform", pch, param, msg_sent) && AdminLevel() >= 50)
|
|
{
|
|
SendVaMessage("Group Formation Set, Please accept!");
|
|
this->PlayerIndex()->GroupInfo.SetFormationName(param);
|
|
this->PlayerIndex()->GroupInfo.SetFormation(1);
|
|
this->PlayerIndex()->GroupInfo.SetPosition(-1);
|
|
this->SendAuxPlayer();
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (strcmp(pch, "goto") == 0)
|
|
{
|
|
success = HandleGotoRequest();
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "groupc") == 0)
|
|
{
|
|
SendVaMessage("Group Count = %d", g_ServerMgr->m_PlayerMgr.GetMemberCount(GroupID()));
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "groupid") == 0)
|
|
{
|
|
SendVaMessage("Group ID = %d", GroupID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "gameid") == 0)
|
|
{
|
|
SendVaMessage("Game ID = %x", GameID());
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
if (strcmp(pch, "hijack") == 0 && ShipIndex()->GetTargetGameID() > 0)
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
success = HandleObjectHijack();
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("You do not have hijack permission.\n" );
|
|
}
|
|
}
|
|
if (strcmp(pch, "heading") == 0)
|
|
{
|
|
float *heading = Heading();
|
|
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, " "));
|
|
SendVaMessage("Current Head: %d Body: %d G: %d", Database()->avatar.head_type, Database()->avatar.body_type,
|
|
Database()->avatar.gender);
|
|
|
|
Database()->avatar.head_type = head;
|
|
Database()->avatar.body_type = body;
|
|
Database()->avatar.gender = gender;
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "helpedit") == 0)
|
|
{
|
|
SendVaMessage("/hijack - take control of object.");
|
|
SendVaMessage("/release - release control of object.");
|
|
SendVaMessage("/exposedecos on - make all decos in sector clickable.");
|
|
SendVaMessage("/exposedecos off - decos unclickable; back to normal.");
|
|
SendVaMessage("/faceme - selected object faces player.");
|
|
SendVaMessage("/panup <value> - pans the selected object up or down by the value (use negative for down).");
|
|
SendVaMessage("/panx <value> - pans selected object in x axis (east/west on map).");
|
|
SendVaMessage("/pany <value> - pans selected object in y axis (north/south on map).");
|
|
SendVaMessage("/panz <value> - pans selected object in z axis (up/down) - same as panup.");
|
|
SendVaMessage("/rotatex <value> - rotates selected object in x axis (roll).");
|
|
SendVaMessage("/rotatey <value> - rotates selected object in y axis (pitch)");
|
|
SendVaMessage("/rotatez <value> - rotates selected object in z axis (yaw)");
|
|
SendVaMessage("/levelout - makes the selected object level - useful after positioning by /hijack.");
|
|
SendVaMessage("/scale <value> - change scale of object to floating point <value> eg 1.2");
|
|
SendVaMessage("/planetspin <value 1...1000> - gives a planet type a rotational spin. 1000 is fast, 1 is slow");
|
|
SendVaMessage("/tilt <value 0...90> - gives a planet type a tilt, in degrees");
|
|
SendVaMessage("/commit (DEV only) - commits changes to selected object to database.");
|
|
SendVaMessage("//rsectors - undo all non-committed changes.");
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strncmp(pch, "helpfield", 9) == 0)
|
|
{
|
|
SendVaMessage("/fradius xxxx - adjust field radius");
|
|
SendVaMessage("/ftype <0-5> - change the field spread type");
|
|
SendVaMessage("/flevel <1-8>");
|
|
SendVaMessage("/fcount xxxx - adjust field asteroid count");
|
|
SendVaMessage("/faddasteroidtype <roid basset> - add additional asteroid type");
|
|
SendVaMessage("/faddore <ore itemID from database> - adds ore choice to field");
|
|
SendVaMessage("/fremoveore <ore itemID from database> - removes ore choice from field");
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'i':
|
|
if (MatchOptWithParam("invite", pch, param, msg_sent))
|
|
{
|
|
long game_id = g_ServerMgr->m_PlayerMgr.GetGameIDFromName(param);
|
|
if (game_id == -1)
|
|
{
|
|
SendVaMessage("Could not find player %s",param);
|
|
return;
|
|
}
|
|
|
|
if (game_id == GameID())
|
|
{
|
|
if (!(AdminLevel() >= 50)) // GM to Admin
|
|
{
|
|
SendVaMessage("Cannot group with yourself!");
|
|
return;
|
|
}
|
|
}
|
|
g_ServerMgr->m_PlayerMgr.GroupInvite(GroupID(),GameID(), game_id);
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'k':
|
|
if (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)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.LeaveGroup(GroupID(),GameID());
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "levelout") == 0)
|
|
{
|
|
success = HandleLevelOutRequest(ShipIndex()->GetTargetGameID());
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("level", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
if (atoi(param) < 0 || atoi(param) > 50)
|
|
{
|
|
SendVaMessage("0 <= Level <= 50");
|
|
return;
|
|
}
|
|
|
|
PlayerIndex()->RPGInfo.SetCombatLevel(atoi(param));
|
|
PlayerIndex()->RPGInfo.SetTradeLevel(atoi(param));
|
|
PlayerIndex()->RPGInfo.SetExploreLevel(atoi(param));
|
|
PlayerIndex()->RPGInfo.SetSkillPoints(atoi(param) * 10);
|
|
LevelUpForSkills();
|
|
UpdateSkills();
|
|
SendAuxPlayer();
|
|
|
|
SendVaMessage("Combat, Explore and Trade LVLs set to %d",atoi(param));
|
|
SendVaMessage("Additionally, you now have %d skillpoints",atoi(param) * 10);
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/level not available at [BETA] and below");
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'm':
|
|
if (MatchOptWithParam("move", pch, param, msg_sent))
|
|
{
|
|
success = HandleMoveRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("mobaggro", pch, param, msg_sent) && AdminLevel() >= 30)
|
|
{
|
|
success = HandleAggroSetting(param);
|
|
msg_sent = true;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
if (strcmp(pch, "ori") == 0)
|
|
{
|
|
float *ori = Orientation();
|
|
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));
|
|
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)
|
|
{
|
|
SendVaMessage("/ore base ore energy,base ore time,base tractor speed");
|
|
SendVaMessage("Base Ore Energy: %d", m_BaseOreEnergy);
|
|
SendVaMessage("Base Ore Time: %.2f", m_BaseOreTime);
|
|
SendVaMessage("Tractor Speed base: %.2f", m_BaseOreTracSpeed);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("New base ore energy: %d", base_energy);
|
|
SendVaMessage("New base ore time: %.2f", base_time);
|
|
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)
|
|
{
|
|
SendVaMessage("ObjectID = 0x%08x",ShipIndex()->GetTargetGameID());
|
|
if (ShipIndex()->GetTargetGameID() != -1)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj) SendVaMessage("%s @ %.2f %.2f %.2f", obj->Name(), obj->PosX(), obj->PosY(), obj->PosZ());
|
|
}
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("panup", pch, param, msg_sent))
|
|
{
|
|
success = HandlePanRequest(param, 3);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("panx", pch, param, msg_sent))
|
|
{
|
|
success = HandlePanRequest(param, 1);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("pany", pch, param, msg_sent))
|
|
{
|
|
success = HandlePanRequest(param, 2);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("panz", pch, param, msg_sent))
|
|
{
|
|
success = HandlePanRequest(param, 3);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("planetspin", pch, param, msg_sent))
|
|
{
|
|
success = HandleSpinRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
if (strcmp(pch, "reffect") == 0)
|
|
{
|
|
//m_SectorMgr->m_EffectManager.RemoveEffectsByPlayer(GameID());
|
|
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(u32 Slot=0;Slot<ShipIndex()->Inventory.GetCargoSpace();Slot++)
|
|
{
|
|
ShipIndex()->Inventory.CargoInv.Item[Slot].Empty();
|
|
}
|
|
|
|
SendVaMessage("Cargo slots = %d", ShipIndex()->Inventory.GetCargoSpace());
|
|
|
|
if (ShipIndex()->Inventory.GetCargoSpace() < 20)
|
|
{
|
|
ShipIndex()->Inventory.SetCargoSpace(20);
|
|
for(u32 i=0;i<ShipIndex()->Inventory.GetCargoSpace();i++)
|
|
{
|
|
ShipIndex()->Inventory.CargoInv.Item[i].Empty();
|
|
}
|
|
SendVaMessage("Restored cargo slots = %d", ShipIndex()->Inventory.GetCargoSpace());
|
|
}
|
|
|
|
SendAuxShip();
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("rotatex", pch, param, msg_sent))
|
|
{
|
|
success = HandleRotateRequest(param, 1);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("rotatey", pch, param, msg_sent))
|
|
{
|
|
success = HandleRotateRequest(param, 2);
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("rotatez", pch, param, msg_sent))
|
|
{
|
|
success = HandleRotateRequest(param, 3);
|
|
msg_sent = true;
|
|
}
|
|
/*
|
|
else if (strcmp(pch, "refreshmissionlist") == 0)
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
LogMessage("Refreshing mission list\n");
|
|
g_ServerMgr->m_Missions.Initialize();
|
|
success = true;
|
|
}
|
|
}
|
|
*/
|
|
else if (strcmp(pch, "resetmounts") == 0)
|
|
{
|
|
ResetWeaponMounts();
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "resetnavs") == 0)
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
memset(m_NavsExplored, 0, sizeof(m_NavsExplored));
|
|
memset(m_NavsExposed, 0, sizeof(m_NavsExposed));
|
|
memset(m_FoundAllSectorNavs, 0, sizeof(m_FoundAllSectorNavs));
|
|
SendVaMessage("All navs have been marked unexplored and undiscovered");
|
|
if (PlayerIndex()->GetSectorNum() <= 9999)
|
|
{
|
|
char thissector[5];
|
|
_snprintf(thissector, 5, "%d\0", PlayerIndex()->GetSectorNum());
|
|
HandleWormholeRequest(thissector);
|
|
}
|
|
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/resetnavs not available at [BETA] and below");
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 's' :
|
|
if (MatchOptWithParam("sounds", pch, param, msg_sent))
|
|
{
|
|
unsigned char Data[256];
|
|
int Index = 0;
|
|
*((int *) &Data[0]) = strlen(param);
|
|
Index += 4;
|
|
strcpy((char *) &Data[Index], param);
|
|
Index += strlen(param);
|
|
*((int *) &Data[Index]) = 1;
|
|
Index += 4;
|
|
*((char *) &Data[Index]) = 0;
|
|
Index += 1;
|
|
SendOpcode(ENB_OPCODE_006A_CLIENT_SOUND, Data, Index);
|
|
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("scale", pch, param, msg_sent))
|
|
{
|
|
success = HandleScaleRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("skillpoints", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
PlayerIndex()->RPGInfo.SetSkillPoints(atoi(param));
|
|
LevelUpForSkills();
|
|
UpdateSkills();
|
|
SendAuxPlayer();
|
|
SendVaMessage("You now have %d skillpoints", atoi(param));
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("scan", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 30) // Beta to Admin
|
|
{
|
|
long scan_range = atoi(param);
|
|
long max_scan = AdminLevel() >= 80 ? 400000 : 80000;
|
|
|
|
if (scan_range >= 1000 && scan_range <= max_scan)
|
|
{
|
|
//ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
m_Stats.ResetStat(STAT_SCAN_RANGE);
|
|
m_Stats.SetStat(STAT_BASE_VALUE, STAT_SCAN_RANGE, (float)scan_range);
|
|
ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
SendVaMessage("Scan range set to %d", scan_range);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Set Scan Range: /scan <1000..%d>", max_scan);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AdminLevel() >= 80) // Dev to Admin
|
|
{
|
|
if (strcmp(pch, "shutdown") == 0)
|
|
{
|
|
LogMessage(">>>> SHUTDOWN issued by %s [%s]\n", Name(), AccountUsername());
|
|
g_ServerMgr->m_PlayerMgr.GlobalAdminMessage("Server shutdown in 30 seconds!");
|
|
GetSectorManager()->AddTimedCall(0, B_SERVER_SHUTDOWN, 15000, NULL);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "sendp") == 0)
|
|
{
|
|
success = true;
|
|
msg_sent = true;
|
|
g_ServerMgr->m_PlayerMgr.SendPlayerWithoutConnection(GameID());
|
|
}
|
|
else if (strcmp(pch, "strings") == 0)
|
|
{
|
|
char buffer[256];
|
|
g_StringMgr->Statistics(buffer);
|
|
SendVaMessage(buffer);
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
else if (strcmp(pch, "stats") == 0)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj && obj->ObjectType() == OT_FIELD)
|
|
{
|
|
Field *f = (Field*)obj;
|
|
SendVaMessage("Stats for field: %s ID[%d]", f->Name(), f->GetDatabaseUID());
|
|
SendVaMessage("Level: %d", f->Level());
|
|
SendVaMessage("Radius: %.1f", f->FieldRadius());
|
|
SendVaMessage("Spread Type: %d", f->GetFieldType());
|
|
SendVaMessage("Roid Count: %d", f->FieldCount());
|
|
success = true;
|
|
msg_sent = true;
|
|
}
|
|
}
|
|
else if (MatchOptWithParam("shieldbuff", pch, param, msg_sent))
|
|
{
|
|
if (param)
|
|
{
|
|
float BuffAmount = (float)atoi(param);
|
|
|
|
this->SetDamageAbsorb(BuffAmount);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Absorb Left: %f", this->GetDamageAbsorb());
|
|
}
|
|
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))
|
|
{
|
|
SendVaMessage("Test Successful!");
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (_strcmpi(pch, "talktree") == 0)
|
|
{
|
|
char string[] =
|
|
"That was one heck of an explotion! 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";
|
|
|
|
SendOpcode(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(this, B_TEST_MESSAGE, time_delay, 0, time_delay);
|
|
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("tilt", pch, param, msg_sent))
|
|
{
|
|
success = HandleTiltRequest(param);
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("terminate", pch, param, msg_sent))
|
|
{
|
|
Player *p = g_ServerMgr->m_PlayerMgr.GetPlayer(param);
|
|
|
|
if (!p)
|
|
{
|
|
p = g_ServerMgr->m_PlayerMgr.GetPlayer(atoi(param) + 0x40000000);
|
|
}
|
|
|
|
//send terminate to net7 proxy
|
|
if (p && AdminLevel() >= 80)
|
|
{
|
|
long player_id = p->GameID();
|
|
SendVaMessage("Terminate player %s [%d]", p->Name(), p->GameID());
|
|
p->SendOpcode(ENB_OPCODE_100A_MVAS_TERMINATE_S_C, (unsigned char *) &player_id, sizeof(long));
|
|
}
|
|
}
|
|
|
|
if (MatchOptWithParam("trade", pch, param, msg_sent))
|
|
{
|
|
// Trade requires that both players recieved a create packet for eachother's ships
|
|
Player * targetp = g_ServerMgr->m_PlayerMgr.GetPlayer(param);
|
|
|
|
if (!targetp)
|
|
{
|
|
SendVaMessage("Could not find player %s",param);
|
|
return;
|
|
}
|
|
|
|
if (targetp->GameID() == GameID())
|
|
{
|
|
if (!(AdminLevel() >= 50)) // GM to Admin
|
|
{
|
|
|
|
SendVaMessage("Cannot trade with yourself!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (targetp->m_TradeID != -1)
|
|
{
|
|
SendVaMessage("Target is already trading");
|
|
return;
|
|
}
|
|
|
|
LogDebug("Clearing trade for players `%s` and `%s`\n",Name(),targetp->Name());
|
|
|
|
for(int x=0;x<6;x++)
|
|
{
|
|
targetp->ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
ShipIndex()->Inventory.TradeInv.Item[x].Empty();
|
|
}
|
|
|
|
SendAuxShip(targetp);
|
|
targetp->SendAuxShip(this);
|
|
|
|
TradeAction(targetp->GameID(),0); // Opens a trade window
|
|
targetp->TradeAction(GameID(), 0); // Open trade window for other player
|
|
m_TradeID = targetp->GameID(); // Set player tradeing with
|
|
m_TradeConfirm = 0;
|
|
targetp->m_TradeID = GameID();
|
|
targetp->m_TradeConfirm = 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;
|
|
SendOpcode(ENB_OPCODE_0065_UI_TRIGGER, (unsigned char *) &Data, Index);
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
else if (MatchOptWithParam("upgrade", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 80) //Dev +
|
|
{
|
|
long upgrade = atoi(param);
|
|
ShipUpgrade(upgrade);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
}
|
|
else if (strcmp(pch, "undockp") == 0)
|
|
{
|
|
success = true;
|
|
msg_sent = true;
|
|
DebugPlayerDock(false);
|
|
//g_ServerMgr->m_PlayerMgr.SendPlayerWithoutConnection(GameID());
|
|
}
|
|
break;
|
|
|
|
case 'w':
|
|
if (strcmp(pch, "who") == 0)
|
|
{
|
|
g_ServerMgr->m_PlayerMgr.ListPlayersAndLocations(this);
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
else if (MatchOptWithParam("warp", pch, param, msg_sent))
|
|
{
|
|
int limit = 10000;
|
|
|
|
if (atoi(param) > limit || atoi(param) < 1000)
|
|
{
|
|
SendVaMessage("Warp limits are between 1000 and %d!", limit);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Setting warp to %d",atoi(param));
|
|
ShipIndex()->CurrentStats.SetWarpSpeed(atoi(param));
|
|
SendAuxShip();
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (MatchOptWithParam("wormhole", pch, param, msg_sent))
|
|
{
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
success = HandleWormholeRequest(param);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/wormhole GM and above only");
|
|
success = false;
|
|
}
|
|
msg_sent = true;
|
|
}
|
|
|
|
if (strcmp(pch, "warpreset") == 0)
|
|
{
|
|
SetWarp();
|
|
TerminateWarp();
|
|
msg_sent = true;
|
|
success = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (!success && !msg_sent)
|
|
{
|
|
SendVaMessage("Illegal slash command: %s", pch);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Player::HandleLogoffRequest(unsigned char *data)
|
|
{
|
|
//LogoffRequest * request = (LogoffRequest *) data;
|
|
LogMessage("Received LogoffRequest for player %s\n",Name());
|
|
|
|
//remove player from the group
|
|
g_ServerMgr->m_PlayerMgr.LeaveGroup(GroupID(),GameID());
|
|
|
|
SendLogoffConfirmation();
|
|
|
|
//disconnect player from TCP if still connected
|
|
if (m_LoginConnection)
|
|
{
|
|
m_LoginConnection->ShutdownTCPLink(GameID());
|
|
}
|
|
|
|
g_ServerMgr->m_PlayerMgr.DropPlayerFromGalaxy(this);
|
|
}
|
|
|
|
void Player::HandleCTARequest(unsigned char *data)
|
|
{
|
|
CTARequest * myCTARequest = (CTARequest *) data;
|
|
|
|
LogMessage("CTA Request:\n");
|
|
DumpBuffer(data, sizeof(CTARequest));
|
|
|
|
g_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;
|
|
|
|
SendOpcode(ENB_OPCODE_00BD_CTA_RESPONSE, (unsigned char *) &CTAResponse, sizeof(CTAResponse));
|
|
}
|
|
|
|
void Player::SendLogoffConfirmation()
|
|
{
|
|
LogMessage("Sending LogoffConfirmation packet\n");
|
|
SendOpcode(ENB_OPCODE_00BA_LOGOFF_CONFIRMATION, 0, 0);
|
|
SendPacketCache();
|
|
}
|
|
|
|
void Player::SendTalkTreeAction(long action)
|
|
{
|
|
//LogMessage("Sending TalkTreeAction packet\n");
|
|
SendOpcode(ENB_OPCODE_0056_TALK_TREE_ACTION, (unsigned char *) &action, sizeof(long));
|
|
}
|
|
|
|
bool Player::HandleRangeRequest()
|
|
{
|
|
bool success = false;
|
|
|
|
if (ShipIndex()->GetTargetGameID() > 0)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
SendVaMessage("Range to object = %f", obj->RangeFrom(Position(), true)); //report absolute range
|
|
success = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleWormholeRequest(char *sector)
|
|
{
|
|
bool success = false;
|
|
bool illegal_dest = false;
|
|
|
|
if (PlayerIndex()->GetSectorNum() > 9999)
|
|
{
|
|
SendVaMessage("Unable to wormhole out of starbase, disembark first.");
|
|
}
|
|
else if (m_SectorMgr)
|
|
{
|
|
TerminateWarp();
|
|
long sector_id = atoi(sector);
|
|
|
|
if (sector_id > 9999)
|
|
{
|
|
sector_id /= 10;
|
|
}
|
|
|
|
if (m_SectorMgr->GetSectorType() != 0 && AdminLevel() != 90)
|
|
{
|
|
illegal_dest = true;
|
|
}
|
|
|
|
char *current_sector_name = g_ServerMgr->GetSectorName(PlayerIndex()->GetSectorNum());
|
|
char *sector_name = g_ServerMgr->GetSectorName(sector_id);
|
|
if (sector_name && !illegal_dest)
|
|
{
|
|
SendVaMessage("Wormhole from %s to %s\n", current_sector_name, sector_name);
|
|
SendVaMessage("Wormhole out of sector %d", PlayerIndex()->GetSectorNum());
|
|
|
|
RemoveFromAllSectorRangeLists();
|
|
|
|
//Hand off server
|
|
m_SectorMgr->SectorServerHandoff(this, sector_id);
|
|
|
|
//set to new server;
|
|
PlayerIndex()->SetSectorNum(sector_id);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Invalid or Illegal Sector ID %d", sector_id);
|
|
}
|
|
}
|
|
|
|
RemoveProspectNodes();
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleKick(char *param)
|
|
{
|
|
char Message[1024];
|
|
|
|
char *name = strtok(param, " ");
|
|
char *reason = 0;
|
|
|
|
if (name)
|
|
reason = strtok(NULL, "");
|
|
else
|
|
return 0;
|
|
|
|
Player * target = g_ServerMgr->m_PlayerMgr.GetPlayer(name);
|
|
|
|
if (!reason)
|
|
{
|
|
reason = new char[50];
|
|
sprintf(reason, "No Reason Given");
|
|
}
|
|
|
|
if (target)
|
|
{
|
|
_snprintf(Message, 1024, "Player '%s' kicked by '%s': %s", target->Name(), Name(), reason);
|
|
LogMessage(" ** Kick: %s\n", Message);
|
|
|
|
target->SendVaMessage("You have been kicked by %s: %s", Name(), reason);
|
|
g_ServerMgr->m_PlayerMgr.GMMessage(Message);
|
|
Sleep(100);
|
|
target->ForceLogout();
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//TODO: spawn a thread to do this, otherwise the GM is waiting for ages for the kick to complete
|
|
void Player::ForceLogout()
|
|
{
|
|
int Count = 0;
|
|
|
|
// Wait 30 seconds for the player to become active, while in space
|
|
/*
|
|
while (!Active() && PlayerIndex()->GetSectorNum() < 10000 && Count < 30)
|
|
{
|
|
Sleep(1000);
|
|
Count++;
|
|
}
|
|
*/
|
|
|
|
// Give them 5 seconds to read the kick message!
|
|
Sleep(5000);
|
|
|
|
long GameIDD = GameID();
|
|
|
|
SendOpcode(ENB_OPCODE_0003_LOGOFF, (unsigned char*)&GameIDD, sizeof(GameIDD));
|
|
SendPacketCache();
|
|
Sleep(100);
|
|
|
|
g_ServerMgr->m_PlayerMgr.LeaveGroup(GroupID(),GameID());
|
|
g_ServerMgr->m_PlayerMgr.DropPlayerFromGalaxy(this);
|
|
/*m_SectorMgr->RemovePlayerFromSectorList(this);
|
|
g_ServerMgr->m_PlayerMgr.UnallocatePlayer(this);*/
|
|
}
|
|
|
|
bool Player::HandleBaseItemListCreate()
|
|
{
|
|
char QueryString[256];
|
|
//ok we run a query on the item database, find all the ores and populate the base_ore_list table
|
|
sprintf(QueryString, "SELECT * FROM `item_base` WHERE `category` = '81'");
|
|
sql_connection_c connection( "net7", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass);
|
|
sql_result_c result;
|
|
sql_result_c *ItemList_result = &result;
|
|
sql_query_c ItemList (&connection);
|
|
sql_query_c ItemUpdate(&connection);
|
|
sql_row_c ItemList_Data;
|
|
|
|
// Execute Query
|
|
ItemList.execute( QueryString );
|
|
ItemList.store(ItemList_result);
|
|
|
|
if (!ItemList_result || !ItemList_result->n_rows())
|
|
return false;
|
|
|
|
for(unsigned int item=0;item < ItemList_result->n_rows(); item++)
|
|
{
|
|
//create this entry in the base_ore_list table
|
|
sql_query BaseItemBuilder;
|
|
ItemList_result->fetch_row(&ItemList_Data);
|
|
long item_id = ItemList_Data["id"];
|
|
const char *name = ItemList_Data["name"];
|
|
|
|
// Loop though each sector
|
|
long sector_id = 0;
|
|
while ((sector_id = g_ServerMgr->m_SectorContent.GetNextSectorID(sector_id)))
|
|
{
|
|
if (sector_id < 9999)
|
|
{
|
|
BaseItemBuilder.Clear();
|
|
BaseItemBuilder.SetTable("base_ore_list");
|
|
BaseItemBuilder.AddData("item_id", item_id);
|
|
BaseItemBuilder.AddData("name", name);
|
|
BaseItemBuilder.AddData("sector_id", sector_id);
|
|
|
|
ItemUpdate.run_query(BaseItemBuilder.CreateQuery());
|
|
}
|
|
}
|
|
}
|
|
|
|
SendVaMessage("Base item list completed.");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Player::HandleAggroSetting(char *param)
|
|
{
|
|
bool success = false;
|
|
long aggro_level = atoi(param);
|
|
char queryString[256];
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
MOB *mob = (0);
|
|
MOBData *mob_data = (0);
|
|
|
|
if (obj && obj->ObjectType() == OT_MOB)
|
|
{
|
|
mob = (MOB*)obj;
|
|
mob_data = g_ServerMgr->MOBList()->GetMOBData(mob->GetMOBType());
|
|
}
|
|
|
|
if (mob && mob_data && (aggro_level >= 0 && aggro_level <=10) && (aggro_level != mob_data->m_Agressiveness))
|
|
{
|
|
success = true;
|
|
long scan_range = ShipIndex()->CurrentStats.GetScanRange();
|
|
ShipIndex()->CurrentStats.SetScanRange(10); //set ship almost blind
|
|
CheckObjectRanges();
|
|
mob_data->m_Agressiveness = (u8)aggro_level;
|
|
|
|
SendVaMessage("Setting mob aggro level of '%s' to %d", mob->Name(), aggro_level);
|
|
|
|
//now save new aggro level in MOB DB
|
|
SendVaMessage("Now commit setting to database.");
|
|
sql_connection_c connection( "net7", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass);
|
|
sql_query_c MobUpdate(&connection);
|
|
|
|
sprintf(queryString, "UPDATE `mob_base` SET `aggressiveness` = '%ld' WHERE `mob_id` = '%d'", aggro_level, mob->GetMOBType());
|
|
MobUpdate.run_query(queryString);
|
|
|
|
Sleep(200);
|
|
ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
ResetRangeLists();
|
|
CheckObjectRanges();
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::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)
|
|
{
|
|
SendVaMessage("/move: syntax: x,y,z");
|
|
SendVaMessage("/move: all parameters float type");
|
|
}
|
|
else
|
|
{
|
|
x = (float)atof(a);
|
|
|
|
if (b != NULL)
|
|
{
|
|
y = (float)atof(b);
|
|
}
|
|
else
|
|
{
|
|
y = PosY();
|
|
}
|
|
|
|
if (c != NULL)
|
|
{
|
|
z = (float)atof(c);
|
|
}
|
|
else
|
|
{
|
|
z = PosZ();
|
|
}
|
|
}
|
|
|
|
if (!this)
|
|
{
|
|
SetPosition(x, y, z);
|
|
|
|
SendVaMessage("Setting position to : %d %d %d", x, y, z);
|
|
|
|
//g_ServerMgr->m_PlayerMgr.SendLocation(this, this);
|
|
//CheckTargetUpdate();
|
|
UpdateVerbs();
|
|
CheckObjectRanges();
|
|
success = true;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
bool Player::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
|
|
{
|
|
SendVaMessage("/orientation: syntax: o1,o2,o3,o4");
|
|
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;
|
|
|
|
SendVaMessage("Targetting 0x%08x Player = 0x%08x",ShipIndex()->GetTargetGameID(), GameID());
|
|
|
|
obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj)
|
|
{
|
|
//New orientation info:
|
|
obj->SetOrientation(o1, o2, o3, o4);
|
|
|
|
SendVaMessage("Object name: %s", obj->Name());
|
|
|
|
obj->SendPosition(this);
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleFaceRequest(long Target)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(Target);
|
|
|
|
if (obj)
|
|
{
|
|
Face(obj);
|
|
SendLocationAndSpeed(true);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleFaceMeRequest(long Target)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(Target);
|
|
|
|
if (obj)
|
|
{
|
|
obj->CalcOrientation(Position(), obj->Position(), true);
|
|
//leave object pointing in correct direction
|
|
obj->SendLocationAndSpeed(true);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleChangeFieldRequest(char *param, int option)
|
|
{
|
|
bool success = false;
|
|
bool change = false;
|
|
bool update_done = false;
|
|
char queryString[256];
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
int value = atoi(param);
|
|
|
|
if (obj && value != 0 && obj->ObjectType() == OT_FIELD)
|
|
{
|
|
sql_connection_c connection( "net7", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass);
|
|
sql_query_c FieldUpdate(&connection);
|
|
Field *f = (Field*)obj;
|
|
|
|
switch (option)
|
|
{
|
|
case 1: //radius
|
|
if (value > 1999)
|
|
{
|
|
f->SetFieldRadius((float)value);
|
|
//commit to DB & re-pop
|
|
sprintf(queryString, "UPDATE `sector_objects_harvestable` SET `max_field_radius` = '%d' WHERE `resource_id` = '%ld'", value, f->GetDatabaseUID());
|
|
change = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("field radius must be 2000 or greater");
|
|
}
|
|
break;
|
|
|
|
case 2: //spread type
|
|
f->SetFieldType(value);
|
|
//commit to DB & re-pop
|
|
sprintf(queryString, "UPDATE `sector_objects_harvestable` SET `field` = '%d' WHERE `resource_id` = '%ld'", value, f->GetDatabaseUID());
|
|
change = true;
|
|
break;
|
|
|
|
case 3: //level
|
|
if (value > 0 && value < 9)
|
|
{
|
|
f->SetLevel(value);
|
|
//commit to DB & re-pop
|
|
sprintf(queryString, "UPDATE `sector_objects_harvestable` SET `level` = '%d' WHERE `resource_id` = '%ld'", value, f->GetDatabaseUID());
|
|
change = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("level must be between 1 and 8");
|
|
}
|
|
break;
|
|
|
|
case 4: //count
|
|
if (value != f->FieldCount())
|
|
{
|
|
SendVaMessage("New asteroid field count: cannot display new changes until server re-start");
|
|
//commit to DB & re-pop
|
|
sprintf(queryString, "UPDATE `sector_objects_harvestable` SET `res_count` = '%d' WHERE `resource_id` = '%ld'", value, f->GetDatabaseUID());
|
|
change = true;
|
|
}
|
|
break;
|
|
|
|
case 5: //add type
|
|
//first check basset is valid
|
|
break;
|
|
|
|
case 6: //add item_id choice to this field
|
|
//1. check item is valid
|
|
if (value > 0 && value < 10000)
|
|
{
|
|
f->AddItemID(value, 0.0f);
|
|
//need to make a new entry
|
|
sql_result_c result;
|
|
sprintf(queryString, "SELECT * FROM sector_objects_harvestable_oretypes WHERE resource_id = '%ld' AND additional_ore_item_id = '%d'", f->GetDatabaseUID(), value);
|
|
FieldUpdate.execute(queryString);
|
|
FieldUpdate.store(&result);
|
|
|
|
if (result.n_rows() == 0)
|
|
{
|
|
sql_query ItemBuilder;
|
|
ItemBuilder.Clear();
|
|
ItemBuilder.SetTable("sector_objects_harvestable_oretypes");
|
|
|
|
ItemBuilder.AddData("resource_id", f->GetDatabaseUID());
|
|
ItemBuilder.AddData("additional_ore_item_id", value);
|
|
ItemBuilder.AddData("frequency", 0);
|
|
|
|
if (!FieldUpdate.run_query(ItemBuilder.CreateQuery()))
|
|
{
|
|
SendVaMessage("Error while comitting new item to DB.");
|
|
}
|
|
}
|
|
change = true;
|
|
update_done = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("invalid item id: %d", value);
|
|
}
|
|
break;
|
|
|
|
default: //
|
|
break;
|
|
}
|
|
|
|
if (change == true)
|
|
{
|
|
if (!update_done) FieldUpdate.run_query(queryString);
|
|
//now blank & re-pop field
|
|
long scan_range = ShipIndex()->CurrentStats.GetScanRange();
|
|
ShipIndex()->CurrentStats.SetScanRange(10); //set ship almost blind
|
|
CheckObjectRanges();
|
|
|
|
//now rebuild field
|
|
f->PopulateField(false, true);
|
|
|
|
ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
ResetRangeLists();
|
|
CheckObjectRanges();
|
|
}
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("No valid asteroid field selected or invalid value.");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandlePanRequest(char *param, int axis)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
float value = (float)atof(param);
|
|
|
|
if (obj && value != 0.0f)
|
|
{
|
|
switch (axis)
|
|
{
|
|
case 1:
|
|
obj->MovePosition(value,0,0);
|
|
break;
|
|
|
|
case 2:
|
|
obj->MovePosition(0,value,0);
|
|
break;
|
|
|
|
case 3:
|
|
obj->MovePosition(0,0,value);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
obj->SendLocationAndSpeed(true);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to move selected object - move amount: %.2f", value);
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleRotateRequest(char *param, int axis)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
float value = (float)atof(param);
|
|
|
|
if (obj && value != 0.0f)
|
|
{
|
|
value = value * PI / 180.0f;
|
|
|
|
float *ori = obj->Orientation();
|
|
|
|
if (ori[0] == 0 && ori[1] == 0 && ori[2] == 0 && ori[3] == 0)
|
|
{
|
|
obj->SetOrientation(0.0f,0.0f,0.0f,1.0f);
|
|
obj->SetHeading();
|
|
obj->LevelOut();
|
|
obj->LevelOrientation();
|
|
}
|
|
else
|
|
{
|
|
obj->SetHeading();
|
|
}
|
|
|
|
switch (axis)
|
|
{
|
|
case 1:
|
|
obj->Rotate(value,0,0);
|
|
break;
|
|
|
|
case 2:
|
|
obj->Rotate(0,value,0);
|
|
break;
|
|
|
|
case 3:
|
|
obj->Rotate(0,0,value);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
obj->SendLocationAndSpeed(true);
|
|
success = true;
|
|
|
|
if (obj->ObjectType() == OT_FIELD)
|
|
{
|
|
Field *f = (Field*)obj;
|
|
//issue field update
|
|
long scan_range = ShipIndex()->CurrentStats.GetScanRange();
|
|
ShipIndex()->CurrentStats.SetScanRange(10); //set ship almost blind
|
|
CheckObjectRanges();
|
|
|
|
//now rebuild field
|
|
f->PopulateField(false, true);
|
|
|
|
ShipIndex()->CurrentStats.SetScanRange(scan_range);
|
|
ResetRangeLists();
|
|
CheckObjectRanges();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to move selected object - move amount: %.2f", value);
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleLevelOutRequest(long Target)
|
|
{
|
|
bool success = false;
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(Target);
|
|
|
|
if (obj)
|
|
{
|
|
obj->SetHeading();
|
|
obj->LevelOut();
|
|
obj->LevelOrientation();
|
|
//leave object square on the Z plane
|
|
obj->SendLocationAndSpeed(true);
|
|
success = true;
|
|
SendVaMessage("%s leveled out", obj->Name());
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleCommitRequest(long Target)
|
|
{
|
|
bool success = false;
|
|
char queryString[256];
|
|
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(Target);
|
|
|
|
if (obj)
|
|
{
|
|
float *ori = obj->Orientation();
|
|
SendVaMessage("Attempting to commit %s to database.", obj->Name());
|
|
sql_connection_c connection( "net7", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass);
|
|
sql_query_c PositionUpdate(&connection);
|
|
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `position_x` = '%.2f' WHERE `sector_object_id` = '%ld'", obj->PosX(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `position_y` = '%.2f' WHERE `sector_object_id` = '%ld'", obj->PosY(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `position_z` = '%.2f' WHERE `sector_object_id` = '%ld'", obj->PosZ(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `orientation_u` = '%.6f' WHERE `sector_object_id` = '%ld'", ori[0], obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `orientation_v` = '%.6f' WHERE `sector_object_id` = '%ld'", ori[1], obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `orientation_w` = '%.6f' WHERE `sector_object_id` = '%ld'", ori[2], obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `orientation_z` = '%.6f' WHERE `sector_object_id` = '%ld'", ori[3], obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects` SET `scale` = '%.4f' WHERE `sector_object_id` = '%ld'", obj->Scale(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
|
|
//store specialist information
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_PLANET:
|
|
sprintf(queryString, "UPDATE `sector_objects_planets` SET `rotate_rate` = '%f' WHERE `planet_id` = '%ld'", obj->Spin(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
sprintf(queryString, "UPDATE `sector_objects_planets` SET `tilt_angle` = '%f' WHERE `planet_id` = '%ld'", obj->Tilt(), obj->GetDatabaseUID());
|
|
PositionUpdate.run_query(queryString);
|
|
break;
|
|
default:
|
|
break;
|
|
} ;
|
|
|
|
SendVaMessage("Object %s committed to Net7 Database.", obj->Name());
|
|
LogMessage("%s just committed changes to object %s %d\n", AccountUsername(), obj->Name(), obj->GetDatabaseUID());
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to commit selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
|
|
bool Player::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
|
|
{
|
|
SendVaMessage("/oeuler: syntax: heading,alt,bank");
|
|
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(ShipIndex()->GetTargetGameID());
|
|
|
|
if (!obj)
|
|
{
|
|
obj = m_CurrentDecoObj;
|
|
}
|
|
|
|
if (obj)
|
|
{
|
|
//New orientation info:
|
|
obj->SetEulerOrientation(o1,o2,o3);
|
|
|
|
SendVaMessage("Object name: %s", obj->Name());
|
|
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();
|
|
SendVaMessage("Setting Quaternion orientation to %.4f,%.4f,%.4f,%.4f",vector[0],vector[1],vector[2],vector[3]);
|
|
|
|
obj->SendPosition(this);
|
|
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleMobCreateRequest(char *param)
|
|
{
|
|
char *pch_parse, *name = 0;
|
|
short level = 0;
|
|
long mob_type = 0;
|
|
long 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 = NearestNav();
|
|
|
|
if (obj)
|
|
{
|
|
if (obj->ObjectType() == OT_STATION && obj->RangeFrom(Position()) < 5000.0f)
|
|
{
|
|
SendVaMessage("You're trying to create a MOB too close to a station. Move to at least 5K away.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef SQL_ENABLE
|
|
if (_stricmp(Name(), "Abramelin") != 0)
|
|
{
|
|
SendVaMessage("createmob has been suspended temporarily - will be replaced by createspawn very soon\n");
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
mob_count = g_ServerMgr->MOBList()->GetMOBCount();
|
|
|
|
pch_parse = strtok(param, " ");
|
|
|
|
if (!pch_parse)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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 (mob_type > -1 && mob_type < mob_count)
|
|
{
|
|
MOB *mob = (MOB*)m_ObjectMgr->AddNewObject(OT_MOB); //MOB creation
|
|
MOBData *mob_data = g_ServerMgr->MOBList()->GetMOBData(mob_type);
|
|
|
|
name = mob_data->m_Name;
|
|
|
|
if (mob && mob_data)
|
|
{
|
|
SendVaMessage("Creating %s at level %d", name, mob_data->m_Level);
|
|
mob->SetMOBType((short)mob_type);
|
|
|
|
mob->SetName(name);
|
|
mob->SetPosition(Position());
|
|
mob->MovePosition(xoffset, 0.0f, -200.0f);
|
|
mob->SetActive(true);
|
|
mob->SetRespawnTick(0);
|
|
mob->SetHostileTo(OT_PLAYER);
|
|
mob->SetVelocity(velocity);
|
|
mob->Turn(turn);
|
|
mob->SetDefaultStats(turn, CURIOUS, velocity, 50);
|
|
mob->SetUpdateRate(50);
|
|
mob->SetBehaviour(CURIOUS);
|
|
mob->AddBehaviourPosition(Position());
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to create MOB at this time.");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Create Mob: /createmob <MOB type>0..%d <level>1..66 <name>", (mob_count - 1));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Player::HandleObjCreateRequest(char *param)
|
|
{
|
|
char *pch_level;
|
|
short level = 0;
|
|
pch_level = strchr(param, ' ');
|
|
|
|
if (strcmp(param, "ON") == 0)
|
|
{
|
|
SendVaMessage("Resource Creation ACTIVATED");
|
|
SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
g_ServerMgr->m_AllowCreate = true;
|
|
return true;
|
|
}
|
|
else if (strcmp(param, "XML") == 0)
|
|
{
|
|
SendVaMessage("XML output on");
|
|
g_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)
|
|
{
|
|
SendVaMessage("Create Asteroid field: /create F <type>1..9 <level>1..8 <count>1.. <radius>1.. ");
|
|
return false;
|
|
}
|
|
else if (AdminLevel() >= 80) // 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(Position());
|
|
obj->PopulateField(true); // issue field
|
|
SendVaMessage("Asteroid field created. Level:%d Count:%d Radius:%d", level, number, radius);
|
|
m_ObjectMgr->DisplayDynamicObjects(this, true); //update display for all roids.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("%s, you can't create an asteroid field ... yet.", Name());
|
|
return false;
|
|
}
|
|
}
|
|
else if (strncmp(param, "M", 1) == 0)
|
|
{
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
if (obj)
|
|
{
|
|
//p->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 (g_ServerMgr->m_AllowCreate == false)
|
|
{
|
|
SendVaMessage("Create Resource: Unable to create resource");
|
|
return false;
|
|
}
|
|
|
|
if (!pch_level)
|
|
{
|
|
SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
return false;
|
|
}
|
|
|
|
long 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((short)object_type + 0x71E);
|
|
obj->SetLevel(level);
|
|
obj->SetPosition(Position());
|
|
obj->ResetResource(); //populate with items
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Create Resource: /create <type>0..12 <level>1..9");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Player::ChangeSectorID(long SectorID)
|
|
{
|
|
PlayerIndex()->SetSectorNum(SectorID);
|
|
}
|
|
|
|
bool Player::HandleFetchRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
if (obj->ObjectType() != OT_PLAYER && obj->ObjectType() != OT_MOB)
|
|
{
|
|
obj->SetPosition(Position());
|
|
SendVaMessage("Object name: %s", obj->Name());
|
|
obj->SendPosition(this); //TODO: send new position to everyone
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to change position of Player or MOB");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleObjectHijack()
|
|
{
|
|
Object *obj;
|
|
ObjectManager *obj_manager = GetObjectManager();
|
|
|
|
if (obj_manager)
|
|
{
|
|
obj = obj_manager->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
}
|
|
|
|
if (obj && HijackObject(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
|
|
SendVaMessage("You have been successfully assigned to control '%s'.", obj->Name());
|
|
LogMessage("HIJACK occurred. Account name '%s'.\n", AccountUsername());
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to hijack object with GameID %d.\n", ShipIndex()->GetTargetGameID());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Player::HandleReleaseHijack()
|
|
{
|
|
if (GetObjectManager() && Hijackee() > 0)
|
|
{
|
|
Object *obj = GetObjectManager()->GetObjectFromID(Hijackee());
|
|
if (obj)
|
|
{
|
|
SendVaMessage("You have been unassigned from control of '%s'.", obj->Name());
|
|
obj->SetVelocity(0);
|
|
obj->SetPlayerHijack(0);
|
|
}
|
|
SetHijackee(0);
|
|
}
|
|
}
|
|
|
|
bool Player::HandleGotoRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
bool admin = false;
|
|
|
|
//only allow admins to jump to resources
|
|
if (AdminLevel() >= 50) // GM to Admin
|
|
{
|
|
admin = true;
|
|
}
|
|
|
|
if (admin == false)
|
|
{
|
|
SendVaMessage("/goto has been disabled");
|
|
return (false);
|
|
}
|
|
|
|
obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
SetPosition(obj->Position());
|
|
SendLocationAndSpeed(true);
|
|
UpdateVerbs();
|
|
CheckObjectRanges();
|
|
CheckNavs();
|
|
success = true;
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
void Player::OpenStargate(long object_id)
|
|
{
|
|
SendActivateNextRenderState(object_id, 1);
|
|
}
|
|
|
|
void Player::CloseStargate(long object_id)
|
|
{
|
|
SendActivateNextRenderState(object_id, 3);
|
|
}
|
|
|
|
bool Player::HandleRenderStateRequest()
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj)
|
|
{
|
|
SendVaMessage("Object '%s'", obj->Name());
|
|
SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
//SendVaMessage("Allowable Render State = 0x%X", obj->allowable_render_states);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleScaleRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
if (m_SectorMgr && (ShipIndex()->GetTargetGameID() > 0 || m_CurrentDecoObj))
|
|
{
|
|
float scale = (float) atof(param);
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (!obj) obj = m_CurrentDecoObj;
|
|
|
|
if (obj)
|
|
{
|
|
if (scale == 0.0)
|
|
{
|
|
// Display current scale
|
|
SendVaMessage("Scale of %s is currently %.2f", obj->Name(), obj->Scale());
|
|
}
|
|
else
|
|
{
|
|
// Set new scale
|
|
SendVaMessage("Changing scale from %g to %g", obj->Scale(), scale);
|
|
obj->SetScale(scale);
|
|
long target_id = obj->GameID();
|
|
if (obj->ObjectType() == OT_RESOURCE)
|
|
{
|
|
// Remove the Object
|
|
obj->Remove();
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
// Recreate the Object
|
|
obj->SendObject(this);
|
|
}
|
|
else
|
|
{
|
|
RemoveObject(target_id);
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
obj->SendObject(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleSpinRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
if (m_SectorMgr && (ShipIndex()->GetTargetGameID() > 0))
|
|
{
|
|
float spin = (float) atof(param);
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj && obj->ObjectType() == OT_PLANET && (spin > 0 && spin < 1001))
|
|
{
|
|
float old_spin = (obj->Spin() - 0.000001f)/0.00001f;
|
|
SendVaMessage("Changing spin from %f to %f", old_spin, spin);
|
|
// Set new spin
|
|
spin = 0.000001f + spin*0.00001f;
|
|
obj->SetSpin(spin);
|
|
long target_id = obj->GameID();
|
|
|
|
RemoveObject(target_id);
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
obj->SendObject(this);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/spin only works on 'Planet' type objects, and must be 1 to 1000");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleTiltRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
if (m_SectorMgr && (ShipIndex()->GetTargetGameID() > 0))
|
|
{
|
|
float tilt = (float) atof(param);
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj && obj->ObjectType() == OT_PLANET && (tilt >= 0 && tilt <= 90))
|
|
{
|
|
// Set new tilt
|
|
SendVaMessage("Changing tilt from %f to %f", (obj->Tilt()*180.0f/PI), tilt);
|
|
tilt = tilt * PI / 180.0f;
|
|
obj->SetTilt(tilt);
|
|
long target_id = obj->GameID();
|
|
|
|
RemoveObject(target_id);
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
obj->SendObject(this);
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("/tilt only works on 'Planet' type objects, and must be 0 to 90");
|
|
}
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleBassetRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
if (m_CurrentDecoObj)
|
|
{
|
|
char msg_buffer[128];
|
|
long basset = atoi(param);
|
|
Object *obj = m_CurrentDecoObj;
|
|
AssetData *asset = g_ServerMgr->AssetList()->GetAssetData(basset);
|
|
|
|
if (asset && asset->m_Name)
|
|
{
|
|
_snprintf(msg_buffer,127, "%ld:%s", basset, asset->m_Name);
|
|
SendPushMessage(msg_buffer, "MessageLine", 3000, 3);
|
|
}
|
|
|
|
// Set new basset
|
|
SendVaMessage("Changing basset from %d to %d", obj->BaseAsset(), basset);
|
|
|
|
obj->SetBasset((short)basset);
|
|
// Remove the Object
|
|
obj->Remove();
|
|
//ensure remove and re-create aren't in same packet stream.
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
// Recreate the Object
|
|
obj->SendObject(this);
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
obj->Remove();
|
|
//ensure remove and re-create aren't in same packet stream.
|
|
SendPacketCache();
|
|
Sleep(200);
|
|
// Recreate the Object
|
|
obj->SendObject(this);
|
|
}
|
|
|
|
return (success);
|
|
}
|
|
|
|
bool Player::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 = g_ServerMgr->m_StationMgr.GetStation(StationID);
|
|
|
|
if (!Stn) // Station not found?
|
|
{
|
|
LogMessage("Station %d not on SQL list\n", StationID);
|
|
return false;
|
|
}
|
|
|
|
LoungeData.Station.StationType = Stn->Type;
|
|
|
|
NPCTemplate * NPCs = NULL;
|
|
x=0;
|
|
for(NPCList::const_iterator npc = Stn->NPCs.begin(); npc < Stn->NPCs.end(); ++npc)
|
|
{
|
|
NPCs = g_ServerMgr->m_StationMgr.GetNPC(*npc);//npc->second;
|
|
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));
|
|
x++;
|
|
}
|
|
LoungeData.NumNPCs = x;
|
|
|
|
RoomTemplate * Rooms;
|
|
x=0;
|
|
for(RoomList::const_iterator room = Stn->Rooms.begin(); room < Stn->Rooms.end(); ++room)
|
|
{
|
|
Rooms = g_ServerMgr->m_StationMgr.GetRoom(*room);
|
|
|
|
LoungeData.Rooms[x].RoomNumber = Rooms->Index;
|
|
LoungeData.Rooms[x].RoomStyle = Rooms->Style;
|
|
LoungeData.Rooms[x].FogFar = Rooms->FogFar;
|
|
LoungeData.Rooms[x].FogNear = Rooms->FogNear;
|
|
x++;
|
|
}
|
|
LoungeData.Station.RoomNumber = x;
|
|
|
|
TermTemplate * Terms;
|
|
x=0;
|
|
for(TermList::const_iterator term = Stn->Terms.begin(); term < Stn->Terms.end(); ++term)
|
|
{
|
|
Terms = g_ServerMgr->m_StationMgr.GetTerminal(*term);
|
|
LoungeData.Terms[x].TermType = Terms->Type;
|
|
LoungeData.Terms[x].Location = Terms->Location;
|
|
LoungeData.Terms[x].RoomNumber = Terms->Room;
|
|
x++;
|
|
}
|
|
LoungeData.NumTerms = x;
|
|
|
|
// Build Packet
|
|
|
|
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];
|
|
|
|
SendOpcode(ENB_OPCODE_0052_LOUNGE_NPC, (unsigned char *) bufferd, Size);
|
|
|
|
//DumpBuffer(bufferd, Size);
|
|
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
//Not too sure on the data structure of this packet
|
|
bool Player::HandleRenderStateInitRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
long render_state = atol(param);
|
|
|
|
if (obj != NULL)
|
|
{
|
|
SendVaMessage("Object '%s'", obj->Name());
|
|
SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendInitRenderState(ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState((short)render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleRenderStateActivateRequest(char *param)
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
long render_state = atol(param);
|
|
obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
SendVaMessage("Object '%s'", obj->Name());
|
|
SendVaMessage("Activate Render State: 2 = open gate half way");
|
|
SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendActivateRenderState(ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState((short)render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleRenderStateActivateNextRequest(char * param)
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
long render_state = atol(param);
|
|
obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
SendVaMessage("Object '%s'", obj->Name());
|
|
SendVaMessage("Activate Next Render State: 1 = Gate opens fully 3 = gate closes");
|
|
SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
SendVaMessage("New Render State = 0x%X", render_state);
|
|
SendActivateNextRenderState(ShipIndex()->GetTargetGameID(), render_state);
|
|
obj->SetRenderState((short)render_state);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
bool Player::HandleRenderStateDeactivate()
|
|
{
|
|
bool success = false;
|
|
Object *obj;
|
|
obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID());
|
|
|
|
if (obj != NULL)
|
|
{
|
|
SendVaMessage("Object '%s'", obj->Name());
|
|
SendVaMessage("Deactivate Render State");
|
|
SendVaMessage("Current Render State = 0x%X", obj->RenderState());
|
|
SendVaMessage("Allowable Render State = 0x%X", 3);
|
|
SendVaMessage("New Render State = 0x%X", 0);
|
|
SendDeactivateRenderState(ShipIndex()->GetTargetGameID());
|
|
obj->SetRenderState(0); //Not sure if I should be changing this here
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
SendVaMessage("Unable to access selected object - could not find object ID");
|
|
}
|
|
return (success);
|
|
}
|
|
|
|
void Player::SendStarbaseAvatarChange(Player *p)
|
|
{
|
|
if (!p) return;
|
|
|
|
StarbaseAvatarChange_S2C change;
|
|
memset(&change, 0, sizeof(change));
|
|
change.AvatarID = p->GameID();
|
|
change.Orient = p->m_Orient;
|
|
change.Position[0] = p->PosX();
|
|
change.Position[1] = p->PosY();
|
|
change.Position[2] = p->PosZ();
|
|
change.ActionFlag = p->ActionFlag();
|
|
change.Room = p->m_Room;
|
|
|
|
SendOpcode(ENB_OPCODE_009E_STARBASE_AVATAR_CHANGE, (unsigned char *) &change, sizeof(change));
|
|
}
|
|
|
|
void Player::HandleStarbaseRequest(unsigned char *data)
|
|
{
|
|
StarbaseRequest * pkt = (StarbaseRequest *) data;
|
|
|
|
LogDebug("Starbase Request - PlayerID: %d Action: %d StarBaseID: %d\n",pkt->PlayerID, pkt->Action, pkt->StarbaseID);
|
|
|
|
NPCTemplate * NPC = NULL;
|
|
|
|
const 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[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 (m_SectorMgr)
|
|
{
|
|
if (m_TradeID != -1)
|
|
{
|
|
CancelTrade();
|
|
}
|
|
LogMessage("Player '%s' Leaving station.\n", Name());
|
|
// 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 (CheckMissions(0, 1, (short)m_StarbaseTargetID, TALK_NPC) ||
|
|
CheckForNewMissions(0, 1, (short)m_StarbaseTargetID) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
NPC = g_ServerMgr->m_StationMgr.GetNPC(m_StarbaseTargetID);
|
|
|
|
// Save our current NPC to make it easier to find
|
|
m_CurrentNPC = NPC;
|
|
|
|
#ifdef USE_MYSQL_STATIONS
|
|
// Get talk tree for NPC
|
|
// and save to m_CurrentTalkTree
|
|
if (NPC && NPC->NPCInteraction.talk_tree.NumNodes > 0)
|
|
{
|
|
long length = GenerateTalkTree(&NPC->NPCInteraction.talk_tree, 1);
|
|
|
|
if (length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Output first node
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) m_TalkTreeBuffer, length);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
m_CurrentTalkTree = (0);
|
|
}
|
|
|
|
m_StarbaseTargetID = pkt->StarbaseID;
|
|
|
|
break;
|
|
case 6: // Activating Job Terminal
|
|
{
|
|
/*
|
|
PacketBuffer buffer;
|
|
|
|
g_ServerMgr->m_Jobs.GetJobList(this, &buffer);
|
|
SendOpcode(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;
|
|
|
|
g_ServerMgr->m_Jobs.GetJobDescription(pkt->StarbaseID, &buffer, &g_ServerMgr->m_TokenParser);
|
|
SendOpcode(ENB_OPCODE_0094_JOB_DESCRIPTION, buffer.getBuffer(), buffer.size());
|
|
|
|
_Item myItem;
|
|
memset(&myItem,0,sizeof(_Item));
|
|
|
|
int itemId = g_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);
|
|
SendItemBase(myItem.ItemTemplateID);
|
|
|
|
PlayerIndex()->RewardInv.Item[0].SetData(&myItem);
|
|
SendAuxPlayer();
|
|
}
|
|
*/
|
|
|
|
break;
|
|
}
|
|
|
|
case 8: // Accept job?
|
|
LogMessage("Accepting Job\n");
|
|
SendOpcode(ENB_OPCODE_0096_JOB_ACCEPT_REPLY);
|
|
// Eventually we'll be able to accept jobs once the system is fixed.
|
|
//g_ServerMgr->m_Missions.givePlayerMission(this, 1);
|
|
break;
|
|
case 9: // ??
|
|
break;
|
|
case 10: // Customize avatar - NOT WORKING YET
|
|
SendOpcode(ENB_OPCODE_0083_RECUSTOMIZE_AVATAR_START);
|
|
break;
|
|
case 11: // Customize starship - NOT WORKING YET
|
|
SendOpcode(ENB_OPCODE_0081_RECUSTOMIZE_SHIP_START);
|
|
}
|
|
}
|
|
|
|
|
|
void Player::SetManufactureID(long mfg_id)
|
|
{
|
|
//LogMessage("Sending SetManufactureID packet\n");
|
|
SendOpcode(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 Player::SendServerHandoff(long from_sector_id, long to_sector_id, const char *from_sector, const char *from_system, const char *to_sector, const 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);
|
|
|
|
LogMessage("Sending ServerHandoff, ToSectorID = %d\n", to_sector_id);
|
|
|
|
SendOpcode(ENB_OPCODE_003A_SERVER_HANDOFF, (unsigned char *) &server_handoff, length);
|
|
|
|
SendPacketCache();
|
|
|
|
ChangeSectorID(to_sector_id);
|
|
}
|
|
|
|
void Player::HandleTriggerEmote(unsigned char *data)
|
|
{
|
|
TriggerEmote * emote = (TriggerEmote *) data;
|
|
|
|
SendNotifyEmote(emote->GameID, emote->Emote);
|
|
}
|
|
|
|
//TODO: Recode using new packet methods
|
|
void Player::HandleChatStream(unsigned char *data)
|
|
{
|
|
ChatStream * chat_stream = (ChatStream *) data;
|
|
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);
|
|
|
|
//SendOpcode(ENB_OPCODE_005F_AVATAR_EMOTE_RESPONSE, buffer, chat_stream->ChatSize + 7);
|
|
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", 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 Player::SendClientChatEvent(int Unknown, int Unknown2, const char * FName, const char * LName, const char * Channel, const 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, Name());
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_00A5_CLIENT_CHAT_EVENT, (unsigned char *) Packet, Index); // Send Packet
|
|
}
|
|
|
|
void Player::SendNotifyEmote(long game_id, long emote)
|
|
{
|
|
NotifyEmote response;
|
|
response.GameID = game_id;
|
|
response.Emote = emote;
|
|
|
|
SendToRangeList(ENB_OPCODE_00A2_NOTIFY_EMOTE, (unsigned char *) &response, sizeof(response));
|
|
}
|
|
|
|
void Player::HandleOption(unsigned char *data)
|
|
{
|
|
OptionPacket * myOption = (OptionPacket *) data;
|
|
|
|
LogMessage("Received Option packet -- GameID=%d OptionType=%d OptionVar=%d\n",
|
|
myOption->GameID, myOption->OptionType, myOption->OptionVar);
|
|
DumpBuffer(data,sizeof(OptionPacket));
|
|
}
|
|
|
|
// This is going to need re-coding in the same way as the Action Packet method
|
|
void Player::HandleSelectTalkTree(unsigned char *data)
|
|
{
|
|
SelectTalkTree * packet = (SelectTalkTree *) data;
|
|
|
|
/*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);
|
|
SetDistressBeacon(false);
|
|
TowToBase();
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 1: // Distress Beacon
|
|
SendTalkTreeAction(-32);
|
|
SetDistressBeacon(true);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 2: // I'm OK
|
|
SendTalkTreeAction(-32);
|
|
SetDistressBeacon(false);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
case 230: // Close
|
|
SendTalkTreeAction(-32);
|
|
m_BeaconRequest = false;
|
|
break;
|
|
}
|
|
|
|
if (!m_BeaconRequest)
|
|
return;
|
|
}
|
|
|
|
if (packet->Selection != 230 && CheckMissions(0, packet->Selection, (short)m_StarbaseTargetID, TALK_NPC))
|
|
{
|
|
m_TradeWindow = true;
|
|
if (packet->Selection == 0)
|
|
{
|
|
SendTalkTreeAction(-32); //close display
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (CheckTalkTree(packet->Selection)) // See if we need a talktree from the database
|
|
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";
|
|
|
|
#ifdef USE_MYSQL_STATIONS
|
|
// Send Item List to Player
|
|
NPCTradeItems();
|
|
#else
|
|
|
|
// 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))
|
|
{
|
|
SendItemBase(item->ItemTemplateID());
|
|
ItemTemp[TotalItems] = item->ItemTemplateID();
|
|
ItemPrice[TotalItems] = item->Cost() * 2;
|
|
TotalItems++;
|
|
}
|
|
}
|
|
|
|
x++;
|
|
}
|
|
|
|
for(x=0; x<TotalItems; x++)
|
|
{
|
|
PlayerIndex()->VendorInv.Item[x].SetItemTemplateID(ItemTemp[x]);
|
|
PlayerIndex()->VendorInv.Item[x].SetStackCount(1);
|
|
PlayerIndex()->VendorInv.Item[x].SetStructure(1.0f);
|
|
PlayerIndex()->VendorInv.Item[x].SetQuality(1.0f);
|
|
PlayerIndex()->VendorInv.Item[x].SetPrice(ItemPrice[x]);
|
|
}
|
|
for (x=TotalItems; x<128; x++)
|
|
{
|
|
PlayerIndex()->VendorInv.Item[x].Clear();
|
|
}
|
|
|
|
SetPrices();
|
|
SendAuxPlayer();
|
|
SendAuxShip();
|
|
#endif
|
|
|
|
SendTalkTreeAction(5);
|
|
SendTalkTreeAction(3);
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
SendTalkTreeAction(6);
|
|
|
|
m_TradeWindow = true;
|
|
}
|
|
|
|
if (packet->Selection == 1 || packet->Selection == 230 )
|
|
{
|
|
SendTalkTreeAction(-32);
|
|
|
|
ClearPrices();
|
|
SendAuxPlayer();
|
|
SendAuxShip();
|
|
}
|
|
}
|
|
|
|
bool Player::CheckTalkTree(int Selection)
|
|
{
|
|
// If we have a talk tree open use this
|
|
if (!m_CurrentNPC) return false;
|
|
|
|
// if Selection is 0 exit!
|
|
if (Selection == 0)
|
|
{
|
|
SendTalkTreeAction(-32); //close display
|
|
return true;
|
|
}
|
|
|
|
long length = GenerateTalkTree(&m_CurrentNPC->NPCInteraction.talk_tree, Selection);
|
|
u16 flags = GetNodeFlags(&m_CurrentNPC->NPCInteraction.talk_tree, Selection);
|
|
|
|
if (length == 0) return false;
|
|
|
|
if (flags == NODE_TRADE)
|
|
{
|
|
// Send Items to Trade
|
|
NPCTradeItems();
|
|
// Send Exit Message
|
|
SendTalkTreeAction(5); // Open Trade Window
|
|
SendTalkTreeAction(3); // Send the "Trade" button
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) m_TalkTreeBuffer, length);
|
|
SendTalkTreeAction(6); // Not sure?
|
|
}
|
|
else
|
|
{
|
|
// Send out Node
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) m_TalkTreeBuffer, length);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Player::NPCTradeItems()
|
|
{
|
|
int TotalItems = 0;
|
|
|
|
if (m_CurrentNPC == NULL)
|
|
return false;
|
|
|
|
ItemBase * item = 0;
|
|
VendorItemList *ItemL;
|
|
|
|
TotalItems = 0;
|
|
for(vecItemList::const_iterator v_item = m_CurrentNPC->Vendor.Items.begin(); v_item < m_CurrentNPC->Vendor.Items.end(); ++v_item)
|
|
{
|
|
ItemL = g_ServerMgr->m_StationMgr.GetVendorItem(*v_item);
|
|
|
|
if (ItemL && (item = g_ItemBaseMgr->GetItem(ItemL->ItemID)) && ItemL->Quanity != 0 )
|
|
{
|
|
// Send ItemBase for every item if needed
|
|
SendItemBase(item->ItemTemplateID());
|
|
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetItemTemplateID(item->ItemTemplateID());
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetStackCount(1);
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetStructure(1.0f);
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetQuality(1.0f);
|
|
|
|
// if we have a set sell price then sell it for that price
|
|
if (ItemL->SellPrice == 0)
|
|
{
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetPrice(item->Cost());
|
|
}
|
|
else
|
|
{
|
|
PlayerIndex()->VendorInv.Item[TotalItems].SetPrice(ItemL->SellPrice);
|
|
}
|
|
|
|
// Make sure we dont go over 128 Items
|
|
TotalItems++;
|
|
}
|
|
if (TotalItems >= 128)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Fill the rest of the inventory with no items
|
|
for (int x=TotalItems; x<128; x++)
|
|
{
|
|
PlayerIndex()->VendorInv.Item[x].Clear();
|
|
}
|
|
|
|
SetPrices();
|
|
SendAuxPlayer();
|
|
SendAuxShip();
|
|
|
|
m_TradeWindow = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Player::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");
|
|
SendOpcode(ENB_OPCODE_0089_RELATIONSHIP, (unsigned char *) &response, sizeof(response));
|
|
}
|
|
|
|
//TODO: Cache this with Net7Proxy
|
|
void Player::HandleGalaxyMapRequest()
|
|
{
|
|
//LogMessage("Received GalaxyMap request packet\n");
|
|
SendOpcode(ENB_OPCODE_2011_GALAXY_MAP_CACHE, 0, 0);
|
|
//SendDataFileToClient("GalaxyMap.dat");
|
|
}
|
|
|
|
void Player::SendGalaxyMap(const char *system, const char *sector, const 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 = GameID();
|
|
|
|
// 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");
|
|
SendOpcode(ENB_OPCODE_0097_GALAXY_MAP, (unsigned char * ) &galaxy_map, (u16)(size + 8));
|
|
}
|
|
|
|
void Player::HandleDebug(unsigned char *data)
|
|
{
|
|
LogDebug("Received Debug packet\n");
|
|
}
|
|
|
|
void Player::SetStartingPosition()
|
|
{
|
|
Object *nearest_nav = (0);
|
|
SetOrientation(0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
|
if (PlayerIndex()->GetSectorNum() > 9999) //stations is simplest case
|
|
{
|
|
SetPosition(0.0f, 0.0f, 0.0f);
|
|
return;
|
|
}
|
|
|
|
ObjectManager *om = this->GetObjectManager();
|
|
|
|
if (m_FromSectorID > 9999)
|
|
{
|
|
// The player just left a station
|
|
// see if we had any entry coords
|
|
if (RestoreDockingCoords())
|
|
{
|
|
//ok let's just check we're within sector boundaries
|
|
SectorManager *sector_manager = GetSectorManager();
|
|
if (sector_manager)
|
|
{
|
|
ServerParameters *params = GetSectorManager()->GetSectorParams();
|
|
float *pos = this->Position();
|
|
if (om && (pos[0] > params->XMax ||
|
|
pos[0] < params->XMin ||
|
|
pos[1] > params->YMax ||
|
|
pos[1] < params->YMin))
|
|
{
|
|
//find nearest nav point, and place player next to it.
|
|
nearest_nav = om->NearestNav(Position());
|
|
SetPosition(nearest_nav->Position());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Object *station = om->FindStation(0);
|
|
if (station)
|
|
{
|
|
int offset = (int)station->Radius();
|
|
SetPosition(station->Position());
|
|
nearest_nav = NearestNav();
|
|
if (nearest_nav)
|
|
{
|
|
Face(nearest_nav);
|
|
SetHeading();
|
|
}
|
|
|
|
// now move the ship forward by the station radius
|
|
ExtrapolatePosition(station->Radius(), 1.0f);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The player just went through a gate
|
|
Object *gate = om->FindGate(m_FromSectorID);
|
|
if (!gate) gate = om->FindFirstNav();
|
|
if (gate)
|
|
{
|
|
// Place the player's ship near the gate
|
|
SetPosition(gate->Position());
|
|
nearest_nav = NearestNav();
|
|
if (nearest_nav)
|
|
{
|
|
Face(nearest_nav);
|
|
SetHeading();
|
|
}
|
|
|
|
// Now move the ship outside of the gate
|
|
ExtrapolatePosition(gate->Radius(), 1.0f);
|
|
}
|
|
else
|
|
{
|
|
SetPosition(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
|
|
if (m_FromSectorID == 0 || (m_FromSectorID == PlayerIndex()->GetSectorNum())) // We just logged in!
|
|
{
|
|
bool success = LoadPosition();
|
|
|
|
if (!success || (PosX() == 0.0f && PosY() == 0.0f && PosZ() == 0.0f))
|
|
{
|
|
LogDebug("Cannot load postion file setting to nearest gate.\n");
|
|
|
|
//find first nav
|
|
Object *obj = om->FindFirstNav();
|
|
|
|
if (!obj)
|
|
{
|
|
obj = om->GetObjectFromID(10000);
|
|
}
|
|
|
|
if (obj)
|
|
{
|
|
SetPosition(obj->Position());
|
|
nearest_nav = NearestNav();
|
|
if (nearest_nav)
|
|
{
|
|
Face(nearest_nav);
|
|
SetHeading();
|
|
}
|
|
ExtrapolatePosition(obj->Radius() + 500.0f, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdateVerbs();
|
|
}
|
|
|
|
void Player::SendMessageString(const 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", Name(), msg);
|
|
}
|
|
|
|
SendOpcode(ENB_OPCODE_001D_MESSAGE_STRING, (unsigned char *) buffer, length + 3);
|
|
}
|
|
|
|
void Player::SendPriorityMessageString(const char *msg1, const 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);
|
|
|
|
SendOpcode(ENB_OPCODE_0020_PRIORITY_MESSAGE, &buffer[0], index);
|
|
}
|
|
|
|
void Player::HandleMissionDismissal(unsigned char *data)
|
|
{
|
|
MissionDismissal *dismiss = (MissionDismissal *)data;
|
|
long MissionID = ntohl(dismiss->MissionID);
|
|
long PlayerID = ntohl(dismiss->PlayerID);
|
|
|
|
MissionDismiss(MissionID);
|
|
}
|
|
|
|
void Player::HandleMissionForfeit(unsigned char *data) //TODO: change handling of forfeit. at the moment, we allow ppl to repeat the mission.
|
|
{
|
|
MissionDismissal *dismiss = (MissionDismissal *)data;
|
|
long MissionID = ntohl(dismiss->MissionID);
|
|
long PlayerID = ntohl(dismiss->PlayerID);
|
|
|
|
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 Player::HandlePetitionStuck(unsigned char *data)
|
|
{
|
|
char *p = (char *) data;
|
|
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 Player::HandleIncapacitanceRequest(unsigned char *data)
|
|
{
|
|
long player = *data; //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";
|
|
|
|
|
|
SendOpcode(ENB_OPCODE_0054_TALK_TREE, (unsigned char *) string, sizeof(string));
|
|
|
|
AvatarDescription avatar;
|
|
memset(&avatar, 0, sizeof(avatar));
|
|
memcpy(&avatar.avatar_data, &Database()->avatar, sizeof(avatar.avatar_data));
|
|
avatar.AvatarID = GameID();
|
|
avatar.unknown3 = 1.0;
|
|
avatar.unknown4 = 1.0;
|
|
SendOpcode(ENB_OPCODE_0061_AVATAR_DESCRIPTION, (unsigned char *) &avatar, sizeof(avatar));
|
|
|
|
m_BeaconRequest = true;
|
|
}
|
|
|
|
void Player::SendWarpIndex(int index)
|
|
{
|
|
SendOpcode(ENB_OPCODE_009C_WARP_INDEX, (unsigned char*) &index, sizeof(index));
|
|
}
|
|
|
|
void Player::WaitForHandoffReceived()
|
|
{
|
|
long counter = 0;
|
|
while (m_UDPHandoffReceived == false && counter < 300)
|
|
{
|
|
Sleep(100);
|
|
counter++;
|
|
}
|
|
|
|
if (counter >= 300)
|
|
{
|
|
LogMessage("UDP wait timed out for player %s\n", Name());
|
|
}
|
|
|
|
m_UDPHandoffReceived = false;
|
|
}
|
|
|
|
void Player::LoginFailed()
|
|
{
|
|
SectorReset();
|
|
m_LoginFailed = true;
|
|
m_NavCommence = true;
|
|
}
|
|
|
|
|
|
|