// PlayerConnection.cpp #pragma warning(disable:4786) #include "PlayerClass.h" #include "ServerManager.h" #include "ObjectManager.h" #include "Opcodes.h" #include "PacketMethods.h" #include "StaticData.h" #include "UDPConnection.h" #include "MOBDatabase.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::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) { 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); } } else { LogMessage("Can't send packet: %04x [%04x]\n", opcode, length); } } 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); } 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_ScratchBuffer, &size, MAXIMUM_PACKET_CACHE, m_PacketSequenceNum)) { if (m_SendQueueBk != m_SendQueue) { LogMessage("!!!! Send Queue overwritten in SendPacketCache!\n"); m_SendQueue = m_SendQueueBk; } #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_ScratchBuffer, size, true); m_PacketSequenceNum++; } } m_Mutex.Unlock(); } m_OpcodeResends = 0; } void Player::IssueTCPBuffer() { if (m_LoginConnection && m_LoginConnection->GameID() == GameID()) { m_LoginConnection->PulseConnectionOutput(); } } //make a separate thread for scanning and re-sending opcodes 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) { if (m_SendQueue->RetreiveMessage(m_ScratchBuffer, &size, MAXIMUM_PACKET_CACHE, packet_num, GameID())) { m_UDPConnection->SendOpcode(ENB_OPCODE_2016_PACKET_SEQUENCE, this, m_ScratchBuffer, 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); } opcode_count--; packet_num++; m_OpcodeResends++; if (m_SendQueueBk != m_SendQueue) { LogMessage("!!!! Send Queue overwritten in ReSendOpcodes!\n"); m_SendQueue = m_SendQueueBk; } } } 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: HandleActionResponse(data); //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() { 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); LogMessage("Handle Sector Login for %s\n", Name()); // Send the sector content to the client - NB AddPlayer must occur before SectorLogin m_SectorMgr->HandleSectorLogin(this); SaveData(); SavePosition(); } } 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_%d.dat", sector_id); GetCurrentDirectory(sizeof(old_path), old_path); SetCurrentDirectory(SERVER_DATABASE_PATH); FILE *f = fopen(lounge_npc, "rb"); if (!f) { sector_id = sector_id / 1000; //no file exists for this station. switch(sector_id) //note: none of these will work and we don't go here anymore { 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(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(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() { char buffer[256]; memset(&buffer, 0, 256); if (m_ActionResponseReceived == false) { SendConfirmedActionOffer(); } else { if (m_PushMissionID != 0) { //now send talk tree as appropriate ProposeMissionTree(m_PushMissionID, 1); m_ActionResponseReceived = false; SendPIPAvatar(-2, m_PushMissionUID, true); } else { //is there any other use for push messages? } } } 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(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 %d\n", start_id); 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 (doesn't appear to be). //check we're targetting a HUSK ObjectManager *om = GetObjectManager(); Object *obj = (0); if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID()); if (obj && obj->ObjectType() == OT_HUSK) { //Now check no-one else is looting this object, and loot timer not active Player *player = obj->CheckResourceLock(); if (player && player != this) { SendVaMessage("%s currently being looted by %s", obj->Name(), player->Name()); } else if (obj->GetPlayerLootLock() != 0 && GetNet7TickCount() < obj->GetLootTime() && obj->GetPlayerLootLock() != this->GameID()) //loot lock still engaged, and this player is not the credited kill player { player = g_PlayerMgr->GetPlayer(obj->GetPlayerLootLock()); if (player == (0)) //player has logged out { goto loot_as_normal; } SendVaMessage("%s credited to %s for %.1f seconds", obj->Name(), player->Name(), ((float)obj->GetLootTime() - (float)GetNet7TickCount())*0.001f); } else { loot_as_normal: long id = ntohl(obj->GameID()); SendOpcode(ENB_OPCODE_008C_LOOT_HULK_PERMISSION, (unsigned char *)&id, sizeof(long)); //see if there are any credits AwardCredits(obj->GetCreditLoot(), 0, true); obj->SetCreditLoot(0); //check if MOB loot is empty if (obj->ResourceRemains() == 0.0f) { obj->SendObjectDrain(-1); } else { m_ProspectWindow = true; } //now mark husk as being available to everyone obj->SetPlayerLootLock(0); obj->SetLootTimer(0); } } } 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 if (InSpace()) { SendLoginCamera(); } } void Player::HandleRequestTime(unsigned char *data) { LogDebug("Received RequestTime packet\n"); // Set the client time SendClientSetTime(*((long *) data)); } //m_ChannelSubscription //I think this also handles requests to subscribe to certain channels void Player::HandleClientChatRequest(unsigned char *data) { ClientChatRequest * request = (ClientChatRequest *) data; char * string1 = ""; char * string2 = ""; char * string3 = ""; char * p_scratch = (char *)m_ScratchBuffer; short length1 = request->string_length; char *p = ((char *) &request->string_length); p += sizeof(short); if (length1 > 0) { string1 = p_scratch; memcpy(string1, p, length1); string1[length1] = 0; p += length1; p_scratch += length1 + 1; } short length2 = *((short *) p); p += sizeof(short); if (length2 > 0) { string2 = p_scratch; memcpy(string2, p, length2); string2[length2] = 0; p += length2; p_scratch += length2 + 1; } short length3 = *((short *) p); p += sizeof(short); if (length3 > 0) { string3 = p_scratch; if (length3 > (MAXIMUM_PACKET_CACHE - 32) ) { length3 = (MAXIMUM_PACKET_CACHE - 32); //prevent overrun for exceptionally verbose messages } memcpy(string3, p, length3); string3[length3] = 0; p += length3; } long unknown2 = *((long *) p); // sprintf(Nick, "%s", string1); //sprintf(Message, "%s", string3); if (request->unknown1 == 1) { g_ServerMgr->m_PlayerMgr.ChatSendPrivate(GameID(), string1, string3); } else 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); } } else if (request->unknown1 == 6) { //subscribe to channel int channel_id = g_PlayerMgr->GetChannelFromName(string2); m_ChannelSubscription[channel_id] = true; } else if (request->unknown1 == 7) { int channel_id = g_PlayerMgr->GetChannelFromName(string2); m_ChannelSubscription[channel_id] = false; } } 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 index = 0; int length = obj->NameLen(); unsigned char packet[256]; AddData (packet, obj->GameID(), index); AddData (packet, (short) 0, index); AddData (packet, (short) (0x1201), index); if (length < 246) { AddDataLS(packet, obj->Name(), index); } else { AddDataLS(packet, "Name of this object too long", index); } *((short *) &packet[4]) = index - 6; SendOpcode(ENB_OPCODE_001B_AUX_DATA, (unsigned char *) packet, index); } void Player::SendAuxNameSignature(Object *obj) { char *name = "d"; 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; //this could have been a stack corruption problem, seems to have gone away now //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, 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(char *msg1, char *type, long time, long priority) { unsigned char packet[512]; memset(packet,0,512); unsigned char *pptr = &packet[0]; int index = 0; if (strlen(msg1) > 480) msg1[481] = 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: Source = *ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].GetData(); if (InvMo.ToInv == 1) //cargo to cargo { Destination = *ShipIndex()->Inventory.CargoInv.Item[InvMo.ToSlot].GetData(); //TODO: check for client hacks: use what the server thinks the client has 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; } //check source is not a 'trade' item. ItemBase * myItem = g_ItemBaseMgr->GetItem(Source.ItemTemplateID); if (myItem && myItem->Category() == 90) { SendVaMessageC(17,"Cannot move trade item into vault."); 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; if (Source.Price <= 0) { SendVaMessage("Vender does not want this item!"); 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; //make sure player actually has this amount, they are not hacking if ((u32)InvMo.Num > Source.StackCount) { InvMo.Num = (long)Source.StackCount; } long trade_stack = InvMo.Num < Source.TradeStack ? InvMo.Num : Source.TradeStack; if (Source.StackCount <= (u32)InvMo.Num) { Destination = g_ItemBaseMgr->EmptyItem; } else { Destination = Source; Destination.StackCount -= InvMo.Num; Destination.TradeStack -= InvMo.Num; } // calculate profit made on this item u64 profit = (Source.Price - (u64)Source.AveCost) * InvMo.Num; //long XP_earned = 50 * myItem->TechLevel() * InvMo.Num); long XP_earned = (long) ((Source.Price > 250 ? 250 : Source.Price - (u64)Source.AveCost) * trade_stack); //profit * 5 LogMessage("Trade Stack = %d Profit = %d\n", trade_stack, (Source.Price - (u64)Source.AveCost)); if (AdminLevel() >= 80 && trade_stack > 0) { long XP_item = (long) (Source.Price - (u64)Source.AveCost); if (XP_item < 0) XP_item = 0; //SendVaMessage("NPC ID %d", m_CurrentNPC); //SendVaMessage("Trade Stack: %d", trade_stack); SendVaMessage("Profit per item: %d", XP_item); //SendVaMessage("Trade XP per item: %d", XP_item); //SendVaMessage("Quality: %d%", (int)(Source.Quality*100.0f)); } AwardCredits(Source.Price * InvMo.Num, XP_earned); 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; } ItemBase * myItem = g_ItemBaseMgr->GetItem(Source.ItemTemplateID); if (myItem && myItem->Category() == 90) { SendVaMessageC(17,"Cannot trade goods."); return; } long item_id = ShipIndex()->Inventory.CargoInv.Item[InvMo.FromSlot].GetItemTemplateID(); 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: Source = *PlayerIndex()->VendorInv.Item[InvMo.FromSlot].GetData(); if (InvMo.ToInv == 1) //buy item { ItemBase * myItem = g_ItemBaseMgr->GetItem(Source.ItemTemplateID); u64 Cost = Source.Price * InvMo.Num; if (PlayerIndex()->GetCredits() < Cost) { SendVaMessageC(17,"Insufficient credits!"); return; } if (Source.Price <= 0) { SendVaMessageC(17,"Vendor will not sell this trade item."); break; } if (myItem->Category() == 90) //trade goods { Source.TradeStack = InvMo.Num; } // Set the buy price for the item Source.Price = GetVenderBuyPrice(Source.ItemTemplateID); Source.StackCount = InvMo.Num; // Trade this many items Source.Quality = 1.0f; if (CargoAddItem(&Source) == 0) //check we have enough space first { PlayerIndex()->SetCredits(PlayerIndex()->GetCredits() - Cost); SaveCreditLevel(); SendAuxPlayer(); SendAuxShip(); } else { SendVaMessageC(17,"Insufficient space in cargo hold."); } } break; // From Loot Window case 6: { Object *obj = 0; if (om) obj = om->GetObjectFromID(ShipIndex()->GetTargetGameID()); if (obj) { switch (obj->ObjectType()) { case OT_HUSK: if (obj->RangeFrom(Position()) > 2000.0f) { SendPushMessage("Target too far to engage tractor beam.", "MessageLine", 3000, 3); } else { 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); 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(""); //check missions if (obj && obj->GetUsedInMission() && obj->RangeFrom(Position()) <= 5000.0f) { CheckMissions(obj->GetDatabaseUID(), 1, obj->GetDatabaseUID(), TALK_SPACE_NPC); CheckForNewMissions(obj->GetDatabaseUID(), 1, obj->GetDatabaseUID()); } } 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); } //Handle Verb icon clicks (actions) 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, m_Confirmation_Ability, GameID()); } // 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, m_Confirmation_Ability, GameID()); } // 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 confirmed 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(); long targetXP = 0; long myXP = 0; //Add other player's items for(x=0;x<6;x++) { //see if there was any tradable on the item's stack //trade_stack = Source.TradeStack; targetXP += CalculateTradeStack(targetp->ShipIndex()->Inventory.TradeInv.Item[x].GetData()); CargoAddItem(targetp->ShipIndex()->Inventory.TradeInv.Item[x].GetData()); } SendAuxShip(); //add items to other player for(x=0;x<6;x++) { myXP += CalculateTradeStack(ShipIndex()->Inventory.TradeInv.Item[x].GetData()); 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); // allocate XP if (targetXP > 0) targetp->AwardTradeXP("Trade:", targetXP); if (myXP > 0) AwardTradeXP("Trade:", myXP); // 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); //NB - this just triggers an effect. When the player arrives, a handoff message is sent 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; } } long Player::CalculateTradeStack(_Item *item) { long XPvalue = 0; //does this item have any trade stack value? if (item->TradeStack > 0) { ItemBase * itembase = g_ItemBaseMgr->GetItem(item->ItemTemplateID); XPvalue = (itembase->Cost() > 250 ? 250 : itembase->Cost()) * item->TradeStack; item->TradeStack = 0; } return XPvalue; } 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 (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 if (isalpha(arg[len])) { return false; } 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; 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 "); 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 'k': { if (strcmp(pch, "killfactions") == 0) { g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Erasing all saved faction data. Data will be reset at next player login."); WipeFactions(); msg_sent = true; success = true; } } break; case 'r': { if (strcmp(pch, "rstations") == 0) { // Read in stations again g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Reloading Stations..."); //SendVaMessage("Reloading Stations..."); g_ServerMgr->m_StationMgr.LoadStations(); g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Station Reload Complete."); //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(); g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Reloading Sectors and mobs..."); //SendVaMessage("Reloading Sectors and mobs..."); g_ServerMgr->m_MOBList.LoadMOBContent(); g_ServerMgr->m_SectorContent.LoadSectorContent(); g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Sector Reload Complete."); //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) { g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Reloading Items..."); //SendVaMessage("Reloading Items..."); g_ServerMgr->m_ItemBaseMgr.Initialize(); g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Items Reloaded."); //SendVaMessage("Items Reloaded."); msg_sent = true; success = true; } else if (strcmp(pch, "rmissions") == 0) { g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Reloading Missions..."); g_ServerMgr->m_Missions.LoadMissionContent(); SendVaMessage("Missions Reloaded."); msg_sent = true; success = true; } else if (strcmp(pch, "rfactions") == 0) { g_ServerMgr->m_PlayerMgr.ChatSendEveryone(GameID(), "Reloading Factions..."); g_ServerMgr->m_FactionData.LoadFactions(); SendVaMessage("Factions Reloaded. You are advised to issue //killfactions now, so player's faction standings are reset on next login"); 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 "); 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 "); 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 "); success = false; msg_sent = true; } } if (MatchOptWithParam("gmenableskills", pch, param, msg_sent)) { char *PlayerName = strtok(param, " "); if (!PlayerName) { SendVaMessage("Syntax: //gmenableskills "); 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 "); 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; } if (AdminLevel() >= 80 && MatchOptWithParam("addbaseore", pch, param, msg_sent)) { success = HandleChangeFieldRequest(param, 7); msg_sent = 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() + 10000; TestBuff.IsPermanent = false; TestBuff.EffectID = 214; // Set stats for buff sprintf(TestBuff.Stats[0].StatName, STAT_SIGNATURE); TestBuff.Stats[0].Value = 300; TestBuff.Stats[0].StatType = STAT_BUFF_VALUE; sprintf(TestBuff.Stats[1].StatName, STAT_SCAN_RANGE); TestBuff.Stats[1].Value = 30000; TestBuff.Stats[1].StatType = STAT_BUFF_VALUE; 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; if (AdminLevel() != 90) Quality = 1.0f; //quality 2.0 seems to cause the quality calculator to output garbage myItem.ItemTemplateID = atoi(ItemIDs); myItem.StackCount = Number; myItem.Price = 200; myItem.Quality = Quality; myItem.Structure = 1; _snprintf(myItem.BuilderName, 63, "%s GM/DEV", Name()); 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 { AwardCredits(_atoi64(param), 0); //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 "); } 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 "); } 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 "); } 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;SlotInventory.GetCargoSpace();Slot++) { ShipIndex()->Inventory.CargoInv.Item[Slot].Empty(); } SendAuxShip(); SendVaMessage("Your inventory is now flushed!"); success = true; msg_sent = true; } else if (strcmp(pch, "factionoverride") == 0) { if (AdminLevel() >= 50) { if (!GetOverrideFaction()) { SendVaMessageC(12, "You can now use all class & faction restricted gates."); SetOverrideFaction(true); } else { SendVaMessageC(12, "You are now class & faction restricted in your gate travel."); SetOverrideFaction(false); } success = true; msg_sent = true; } else { SendVaMessage("Override faction command not available"); } } } 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) { SendConfirmedActionOffer(); success = true; msg_sent = true; } /*TODO: SendVaMessage("/faddore - adds ore choice to field"); SendVaMessage("/fremoveore - 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 - pans the selected object up or down by the value (use negative for down)."); SendVaMessage("/panx - pans selected object in x axis (east/west on map)."); SendVaMessage("/pany - pans selected object in y axis (north/south on map)."); SendVaMessage("/panz - pans selected object in z axis (up/down) - same as panup."); SendVaMessage("/rotatex - rotates selected object in x axis (roll)."); SendVaMessage("/rotatey - rotates selected object in y axis (pitch)"); SendVaMessage("/rotatez - rotates selected object in z axis (yaw)"); SendVaMessage("/levelout - makes the selected object level - useful after positioning by /hijack."); SendVaMessage("/scale - change scale of object to floating point eg 1.2"); SendVaMessage("/setradius - used on its own, this will set the server's idea of the size of the object."); SendVaMessage(" ... it will set the radius to the distance you are from the object targetted."); SendVaMessage("/setradius - change the server's idea of the size of the object to "); SendVaMessage("/signature - change sig of object to floating point eg 20000"); SendVaMessage("/planetspin - gives a planet type a rotational spin. 1000 is fast, 1 is slow"); SendVaMessage("/tilt - 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 - add additional asteroid type"); SendVaMessage("/faddore - adds ore choice to field"); SendVaMessage("/fremoveore - removes ore choice from field"); SendVaMessage("/addbaseore - adds ore choice to all fields in this sector"); SendVaMessage("/removebaseore - removes ore choice from all fields in this sector."); SendVaMessage(" note that field ore choices override base ore choices, so you could have a sector with a certain ore in one field only."); 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(); SaveAdvanceLevel(XP_COMBAT, atoi(param)); SaveAdvanceLevel(XP_EXPLORE, atoi(param)); SaveAdvanceLevel(XP_TRADE, atoi(param)); 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 'n': if (strcmp(pch, "noattack") == 0 && AdminLevel() >= 50) { SendVaMessageC(17, "Combat immunity %s", m_CombatImmunity ? "off" : "on" ); m_CombatImmunity = !m_CombatImmunity; msg_sent = true; success = 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;SlotInventory.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;iInventory.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 (AdminLevel() >= 80 && MatchOptWithParam("removebaseore", pch, param, msg_sent)) { success = HandleChangeFieldRequest(param, 8); 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, "resetchar") == 0) { if (AdminLevel() >= 30) // GM to Admin { SendVaMessageC(17, "Character %s reset to zero", Name()); success = true; msg_sent = true; ForceLogout(); WipeCharacter(); //when they next login, should be back to normal. } } 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)) { if (param) { SendClientSound(param); } 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("stat", pch, param, msg_sent)) { if (AdminLevel() >= 80) // Beta to Admin { char *stat = strtok(param, " "); char *types = strtok(NULL, " "); char *values = strtok(NULL, " "); int type = 0; float value = 0.0f; //beta testers will break this - add checking if (types) type = atoi(types); if (values) value = (float) atof(values); if (stat && type >= 0 && type < 5) { m_Stats.SetStat(type, stat, value, "USER_TEST"); m_Stats.UpdateAux(stat); SendAuxShip(); SendVaMessage("Update stat %s", stat); success = true; msg_sent = true; } else { SendVaMessage("Usage: stat > "); } } } 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); m_Stats.UpdateAux(STAT_SCAN_RANGE); SendAuxShip(); 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 (MatchOptWithParam("signature", pch, param, msg_sent)) { success = HandleNavChangeRequest(param, 1); msg_sent = true; } else if (strcmp(pch, "setradius") == 0) { success = HandleNavChangeRequest(0, 2); msg_sent = true; } else if (MatchOptWithParam("setradius", pch, param, msg_sent)) { success = HandleNavChangeRequest(param, 2); msg_sent = true; } 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()); Field *f; MOB *m; StaticMap *s; if (obj) { switch (obj->ObjectType()) { case OT_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; break; case OT_NAV: case OT_PLANET: case OT_DECO: case OT_CAPSHIP: case OT_STATION: case OT_STARGATE: s = (StaticMap*)obj; SendVaMessage("Stats for Nav: %s ID[%d]", s->Name(), s->GetDatabaseUID()); SendVaMessage("Sig: %.1f", s->Signature()); SendVaMessage("Radar Range: %.1f", s->RadarRange()); SendVaMessage("Server radius: %.1f", s->Radius()); SendVaMessage("Scale: %.3f", s->Scale()); SendVaMessage("Nav Type: %d", s->NavType()); if (obj->GetFactionID() > 0) { char *name = g_ServerMgr->m_FactionData.GetFactionName(obj->GetFactionID()); float standing = GetFactionStanding(obj); SendVaMessage("Faction ID %d [%s]", obj->GetFactionID(), name); SendVaMessage("Your standing with that faction: %.1f", standing); } if (obj->GetClassSpecific()) { SendVaMessage("Gate is class specific."); if (obj->GetFactionID() < 1) { SendVaMessageC(17, "Database error: class specific chosen, no faction specified. Use DASE to change faction affiliation."); } } success = true; msg_sent = true; break; case OT_MOB: m = (MOB*)obj; SendVaMessage("Stats for MOB: %s GameID[%d]", m->Name(), m->GameID()); SendVaMessage("Scale: %.3f", m->Scale()); SendVaMessage("MOB Type ID: %d", m->GetMOBType()); if (m->GetSpawnName()) SendVaMessage("Part of Spawn name: %s", m->GetSpawnName()); success = true; msg_sent = true; break; default: break; } } } 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 (!PlayerInRangeList(targetp)) { SendVaMessageC(17,"%s needs to be closer for trade", targetp->Name()); } 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()); } else if (strcmp(pch, "uptime") == 0) { success = true; msg_sent = true; int RSec = GetNet7TickCount() / 1000; int Sec = RSec % 60; int Min = (RSec/60) % 60; int Hours = (RSec/3600); SendVaMessage("Uptime: %d Hour(s) %d Min(s) %d Sec(s)", Hours, Min, Sec); } 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 = 6000; if (AdminLevel() >= 30) //Beta + { 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); } void Player::WormHole(int sector_id) { struct WeftList { int SectorID; char * Name; long ObjectID; }; WeftList ListOfWefts[] = { 1910, "Maeldun's Weft", 137, 1070, "Virgil's Weft", 1094, 4120, "Arion`s Weft", 1646, 1705, "Hagoth's Weft", 2906, 1077, "Hagoth's Weft", 52, 4520, "Yamuna's Weft", 1557, 2210, "Brendan's Weft", 624 }; char * WeftName = NULL; long WeftID = 0; RemoveFromAllSectorRangeLists(); // Leave formation if in one g_ServerMgr->m_PlayerMgr.BreakFormation(GameID()); g_ServerMgr->m_PlayerMgr.LeaveFormation(GameID()); //Hand off server m_SectorMgr->SectorServerHandoff(this, sector_id); //set to new server; PlayerIndex()->SetSectorNum(sector_id); // Find the Weft Name for(int x=0;x<7;x++) { if (ListOfWefts[x].SectorID == sector_id) { WeftName = ListOfWefts[x].Name; WeftID = ListOfWefts[x].ObjectID; } } // Set your location at the weft SectorManager *sm = g_ServerMgr->GetSectorManager((long) sector_id); if (sm && WeftName) { ObjectManager *om = sm->GetObjectManager(); Object *weft = om->GetObjectFromName(g_StringMgr->GetStr(WeftName)); if (weft) { this->SetPosition(weft->Position()); } } } 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(int item=0;itemn_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"]; 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` = '%d' 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::HandleNavChangeRequest(char *param, int option) { bool success = false; bool change = false; bool update_done = false; char queryString[256]; Object *obj = m_ObjectMgr->GetObjectFromID(ShipIndex()->GetTargetGameID()); float value = 0; if (param) value = (float)atof(param); if (obj && (obj->ObjectType() == OT_NAV || obj->ObjectType() == OT_DECO || obj->ObjectType() == OT_PLANET || obj->ObjectType() == OT_CAPSHIP || obj->ObjectType() == OT_STATION) ) { sql_connection_c connection( "net7", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass); sql_query_c NavUpdate(&connection); StaticMap *s = (StaticMap*)obj; switch (option) { case 1: //signature if (value > 1999) { SendVaMessageC(12, "Setting %s signature to %.2f (Commit to DB)", obj->Name(), value); LogMessage("%s changed %s sig to: %.2f\n", AccountUsername(), obj->Name(), value); s->SetSignature(value); //commit to DB sprintf(queryString, "UPDATE `sector_nav_points` SET `signature` = '%f' WHERE `sector_object_id` = '%d'", value, s->GetDatabaseUID()); change = true; } else { SendVaMessage("signature must be 2000 or greater"); } break; case 2: //server radius if (value == 0) { //determine range to target value = obj->RangeFrom(Position(), true); } SendVaMessageC(12, "Setting %s server radius to %.2f (Commit to DB)", obj->Name(), value); LogMessage("%s changed %s radius to: %.2f\n", AccountUsername(), obj->Name(), value); s->SetObjectRadius(value); sprintf(queryString, "UPDATE `sector_nav_points` SET `object_radius_patch` = '%f' WHERE `sector_object_id` = '%d'", value, s->GetDatabaseUID()); change = true; break; default: break; } success = true; if (change == true) { NavUpdate.run_query(queryString); } } else { SendVaMessage("No valid nav object selected or invalid value."); } 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` = '%d'", 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` = '%d'", 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` = '%d'", 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` = '%d'", 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 = '%d' 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; case 7: //add base ore to 'base_ore_list' //1. check item is valid if (value > 0 && value < 10000) { ItemBase *base_ore = g_ItemBaseMgr->GetItem(value); //is this ore already in the DB? sql_result_c result; sprintf(queryString, "SELECT * FROM base_ore_list WHERE sector_id = '%d' AND item_id = '%d'", PlayerIndex()->GetSectorNum(), value); FieldUpdate.execute(queryString); FieldUpdate.store(&result); if (result.n_rows() == 0 && base_ore) { sql_query ItemBuilder; ItemBuilder.Clear(); ItemBuilder.SetTable("base_ore_list"); ItemBuilder.AddData("name", base_ore->Name()); ItemBuilder.AddData("item_id", value); ItemBuilder.AddData("frequency", 0); ItemBuilder.AddData("sector_id", (long)PlayerIndex()->GetSectorNum()); if (!FieldUpdate.run_query(ItemBuilder.CreateQuery())) { SendVaMessage("Error while comitting new item to DB."); } else { SendVaMessageC(13, "Added %s to base ores for sector %s.", base_ore->Name(), PlayerIndex()->GetSectorName()); } } change = true; update_done = true; } else { SendVaMessage("invalid item id: %d", value); } break; case 8: //remove base ore //1. check item is valid if (value > 0 && value < 10000) { ItemBase *base_ore = g_ItemBaseMgr->GetItem(value); //delete from DB if (base_ore) { sprintf(queryString, "DELETE FROM base_ore_list WHERE sector_id = '%d' AND item_id = '%d'", PlayerIndex()->GetSectorNum(), value); change = true; SendVaMessageC(13, "%s removed from Base Ore list.", base_ore->Name()); } } 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 levelled 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` = '%d'", obj->PosX(), obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `position_y` = '%.2f' WHERE `sector_object_id` = '%d'", obj->PosY(), obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `position_z` = '%.2f' WHERE `sector_object_id` = '%d'", obj->PosZ(), obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `orientation_u` = '%.6f' WHERE `sector_object_id` = '%d'", ori[0], obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `orientation_v` = '%.6f' WHERE `sector_object_id` = '%d'", ori[1], obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `orientation_w` = '%.6f' WHERE `sector_object_id` = '%d'", ori[2], obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `orientation_z` = '%.6f' WHERE `sector_object_id` = '%d'", ori[3], obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects` SET `scale` = '%.4f' WHERE `sector_object_id` = '%d'", 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` = '%d'", obj->Spin(), obj->GetDatabaseUID()); PositionUpdate.run_query(queryString); sprintf(queryString, "UPDATE `sector_objects_planets` SET `tilt_angle` = '%f' WHERE `planet_id` = '%d'", 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, DRIFT, velocity, 50); mob->SetUpdateRate(50); mob->SetBehaviour(DRIFT); mob->AddBehaviourPosition(Position()); return true; } else { SendVaMessage("Unable to create MOB at this time."); return false; } } else { SendVaMessage("Create Mob: /createmob 0..%d 1..66 ", (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 0..12 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 1..9 1..8 1.. 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 0..12 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 0..12 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, "%d:%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;xGetObjectFromID(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; 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, m_StarbaseTargetID, TALK_NPC) || CheckForNewMissions(0, 1, 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, char *from_sector, char *from_system, char *to_sector, char *to_system) { // Check for invalid destinations if (to_sector == 0 || to_sector_id == 0 || to_system == 0) { LogMessage("FATAL ERROR! Invalid server handoff destination! Returning to source\n"); to_sector = from_sector; to_sector_id = from_sector_id; to_system = from_system; } ServerHandoff server_handoff; memset(&server_handoff, 0, sizeof(server_handoff)); server_handoff.join = m_MasterJoin; server_handoff.join.ToSectorID = ntohl(to_sector_id); server_handoff.join.FromSectorID = ntohl(from_sector_id); // Populate "FROM SECTOR" string char *p = (char *) &server_handoff.variable_data; *((short *) p) = strlen(from_sector); p += 2; strncpy(p, from_sector, strlen(from_sector)); p += strlen(from_sector); // Populate "FROM SYSTEM" string *((short *) p) = strlen(from_system); p += 2; strncpy(p, from_system, strlen(from_system)); p += strlen(from_system); // Populate "TO SECTOR" string *((short *) p) = strlen(to_sector); p += 2; strncpy(p, to_sector, strlen(to_sector)); p += strlen(to_sector); // Populate "TO SYSTEM" string *((short *) p) = strlen(to_system); p += 2; strncpy(p, to_system, strlen(to_system)); p += strlen(to_system); size_t length = (p - (char *) &server_handoff); 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, char * FName, char * LName, char * Channel, char * Message) { unsigned char Packet[1024]; int Index = 0; AddData(Packet, Unknown, Index); // Not sure what this is usualy its 0x03 AddData(Packet, Unknown2, Index); // Not sure what this is usualy its 0x00 AddDataLS(Packet, FName, Index); // First Name of Player AddDataLS(Packet, LName, Index); // Last Name of Player AddData(Packet, (short) 0, Index); // ? End Marker I think ? AddDataLS(Packet, Channel, Index); // Channel it came from AddDataLS(Packet, Message, Index); // Message AddData(Packet, 0, Index); // ? End Marker I think ? AddData(Packet, (short) 0, Index); // ? End Marker I think ? if (0/*log*/) //TODO: add chat logging global { // Log all chat messages to the chat log. LogChatMsg("%s->[%s]> \"%s\" (%s)\n", FName, Channel, Message, 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) { if (CheckMissions(0, packet->Selection, m_StarbaseTargetID, TALK_NPC) ) { m_TradeWindow = true; if (packet->Selection == 0) { SendTalkTreeAction(-32); //close display m_PushMissionID = 0; m_PushMissionUID = 0; } 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"; // Send Item List to Player NPCTradeItems(); 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); m_PushMissionID = 0; m_PushMissionUID = 0; 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 ) { if (item->Category() == 90 && ItemL->SellPrice <= 0) { continue; //Don't display this item, it's not for sale! } // 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 if (ItemL->SellPrice == -1) // We are not selling this item { // We are not selling this item TotalItems--; } 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(char *system, char *sector, char *station) { struct GalaxyMap { long Type; long Size; long PlayerID; char Variable[64]; long unknown; }; GalaxyMap galaxy_map; long string_length; long size = 8; // include PlayerID and unknown char *p = galaxy_map.Variable; galaxy_map.Type = 4; galaxy_map.PlayerID = CharacterID(); // 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 we can't find a gate we probaly worm holed here if (!gate) { //gate = om->FindFirstNav(); long sector_id = this->PlayerIndex()->GetSectorNum(); struct WeftList { int SectorID; char * Name; long ObjectID; }; // List of wefts WeftList ListOfWefts[] = { 1910, "Maeldun's Weft", 137, 1070, "Virgil's Weft", 1094, 4120, "Arion`s Weft", 1646, 1705, "Hagoth's Weft", 2906, 1077, "Hagoth's Weft", 52, 4520, "Yamuna's Weft", 1557, 2210, "Brendan's Weft", 624 }; char * WeftName = NULL; long WeftID = 0; // Find the Weft Name for(int x=0;x<7;x++) { if (ListOfWefts[x].SectorID == sector_id) { WeftName = ListOfWefts[x].Name; WeftID = ListOfWefts[x].ObjectID; } } // Set your location at the weft SectorManager *sm = g_ServerMgr->GetSectorManager((long) sector_id); if (sm && WeftName) { ObjectManager *om = sm->GetObjectManager(); gate = om->GetObjectFromName(g_StringMgr->GetStr(WeftName)); } } 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(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(char *msg1, char *msg2, long time, long priority) { unsigned char buffer[512]; int index = 0; memset(buffer, 0, sizeof(buffer)); AddDataSN(buffer, msg1, index); AddDataSN(buffer, msg2, index); AddData(buffer, time, index); AddData(buffer, priority, index); 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; 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)); if (!m_IncapAvatarSent) { m_IncapAvatarSent = true; // Send Avatar ID to show up in talk tree PlayerIndex()->SetPIPAvatarID(-3); SendAuxPlayer(); StationTemplate * Stn = g_ServerMgr->m_StationMgr.GetStation(m_RegisteredSectorID); if (!Stn) { Stn = g_ServerMgr->m_StationMgr.GetStation(10711); //Net7 if (!Stn) return; } NPCTemplate * NPCs = g_ServerMgr->m_StationMgr.GetNPC(Stn->NPCs[0]); if (!NPCs) return; AvatarDescription avatar; memset(&avatar, 0, sizeof(avatar)); memcpy(&avatar.avatar_data, &NPCs->Avatar, sizeof(avatar.avatar_data)); NPCs->Avatar.shirt_primary_color[0] += 0.1f; NPCs->Avatar.shirt_primary_color[1] -= 0.1f; NPCs->Avatar.shirt_primary_color[2] += 0.15f; sprintf(avatar.avatar_data.avatar_first_name, "Station\0"); sprintf(avatar.avatar_data.avatar_last_name, "Mechanic\0"); avatar.AvatarID = -3; 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; } void Player::SendPIPAvatar(long game_id, long avatar_id, bool actual_use) { RemoveObject(game_id); // Send Avatar ID to show up in talk tree PlayerIndex()->SetPIPAvatarID(game_id); SendAuxPlayer(); //get a random NPC face for now mapNPCs *npc_list = g_ServerMgr->m_StationMgr.GetNPCList(); NPCTemplate * NPC = NULL; Object *obj = g_SectorObjects[avatar_id]; if (!obj) return; long index = avatar_id%200; AvatarDescription avatar; memset(&avatar, 0, sizeof(avatar)); //get a random avatar from the station NPC list for(mapNPCs::const_iterator npc = npc_list->begin(); npc != npc_list->end(); ++npc) { if (index-- <= 0) //choose this NPC { memcpy(&avatar.avatar_data, &npc->second->Avatar, sizeof(avatar.avatar_data)); break; } } avatar.avatar_data.shirt_primary_color[0] += 0.1f; avatar.avatar_data.shirt_primary_color[1] -= 0.1f; avatar.avatar_data.shirt_primary_color[2] += 0.15f; if (actual_use) { long len = strlen(obj->Name()); bool split = false; if (len > 20) { //split the name between first and last names //trace back from just after the centre first long centre = len/2 + 4; char *ptr = obj->Name(); while (centre > 0) { if (ptr[centre] == ' ') { strncpy(avatar.avatar_data.avatar_first_name, ptr, centre); strncpy(avatar.avatar_data.avatar_last_name, ptr + centre, len-centre); split = true; break; } centre--; } } if (!split) { strncpy(avatar.avatar_data.avatar_first_name, obj->Name(), 20); memset(avatar.avatar_data.avatar_last_name, 0, 20); } } else { sprintf(avatar.avatar_data.avatar_first_name, "Station\0"); sprintf(avatar.avatar_data.avatar_last_name, "Mechanic\0"); } avatar.AvatarID = game_id; avatar.unknown3 = 1.0; avatar.unknown4 = 1.0; SendOpcode(ENB_OPCODE_0061_AVATAR_DESCRIPTION, (unsigned char *) &avatar, sizeof(avatar)); }