/** @file * * @par History * - 2006/05/23 Shinigami: send_full_statmsg() updated to support Elfs * - 2009/07/23 MuadDib: updates for new Enum::Packet Out ID * - 2009/08/09 MuadDib: Re factor of Packet 0x25, 0x11 for naming convention * - 2009/09/06 Turley: Changed Version checks to bitfield client->ClientType * - 2009/12/02 Turley: fixed 0x11 packet (race flag) */ #include "statmsg.h" #include "../clib/clib.h" #include "../clib/rawtypes.h" #include "globals/network.h" #include "globals/settings.h" #include "mobile/charactr.h" #include "network/client.h" #include "network/packethelper.h" #include "network/packets.h" #include "ufunc.h" #include "uoclient.h" namespace Pol { namespace Core { using namespace Network::PktHelper; void send_full_statmsg( Network::Client* client, Mobile::Character* chr ) { PacketOut msg; msg->offset += 2; // msglen msg->Write( chr->serial_ext ); msg->Write( chr->name().c_str(), 30, false ); bool ignore_caps = Core::settingsManager.ssopt.core_ignores_defence_caps; if ( networkManager.uoclient_general.hits.any ) { int v = chr->vital( networkManager.uoclient_general.hits.id ).current_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); // hits v = chr->vital( networkManager.uoclient_general.hits.id ).maximum_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); // max_hits } else { msg->WriteFlipped( 0u ); // hits msg->WriteFlipped( 0u ); // max_hits } msg->Write( 0u ); // (client->chr->can_rename( chr ) ? 0xFF : 0); if ( client->ClientType & Network::CLIENTTYPE_70300 ) msg->Write( 6u ); // New entries for classic client else if ( ( client->UOExpansionFlag & Network::ML ) && ( client->ClientType & Network::CLIENTTYPE_5000 ) ) msg->Write( 5u ); // Set to ML level else if ( ( client->UOExpansionFlag & Network::AOS ) ) msg->Write( 4u ); // Set to AOS level statbar for full info else msg->Write( 1u ); // Set to oldschool statbar info. // if (chr->race == Plib::RACE_ELF) // msg->Write(static_cast(chr->gender | FLAG_RACE)); // else msg->Write( chr->gender ); // GENDER_MALE or GENDER_FEMALE (see ../plib/uconst.h) if ( networkManager.uoclient_general.strength.any ) { int v = chr->attribute( networkManager.uoclient_general.strength.id ).effective(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); } else msg->WriteFlipped( 0u ); if ( networkManager.uoclient_general.dexterity.any ) { int v = chr->attribute( networkManager.uoclient_general.dexterity.id ).effective(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); } else msg->WriteFlipped( 0u ); if ( networkManager.uoclient_general.intelligence.any ) { int v = chr->attribute( networkManager.uoclient_general.intelligence.id ).effective(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); } else msg->WriteFlipped( 0u ); if ( networkManager.uoclient_general.stamina.any ) { int v = chr->vital( networkManager.uoclient_general.stamina.id ).current_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); v = chr->vital( networkManager.uoclient_general.stamina.id ).maximum_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); } else { msg->WriteFlipped( 0u ); msg->WriteFlipped( 0u ); } if ( networkManager.uoclient_general.mana.any ) { int v = chr->vital( networkManager.uoclient_general.mana.id ).current_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); v = chr->vital( networkManager.uoclient_general.mana.id ).maximum_ones(); if ( v > 0xFFFF ) v = 0xFFFF; msg->WriteFlipped( static_cast( v ) ); } else { msg->WriteFlipped( 0u ); msg->WriteFlipped( 0u ); } msg->WriteFlipped( chr->gold_carried() ); // Adjusted to work with Physical Resist if AOS client, and AOS Resistances enabled. if ( ( client->UOExpansionFlag & Network::AOS ) && client->aosresist ) { s16 value = chr->physical_resist().sum(); if ( chr->has_physical_resist_cap() && !ignore_caps ) { auto cap = chr->physical_resist_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); } else msg->WriteFlipped( chr->ar() ); unsigned int weight = chr->weight(); Clib::sanitize_upperlimit( &weight, 0xFFFFu ); msg->WriteFlipped( weight ); // moreinfo 5 if ( ( client->UOExpansionFlag & Network::ML ) && ( client->ClientType & Network::CLIENTTYPE_5000 ) ) { msg->WriteFlipped( chr->carrying_capacity() ); msg->Write( chr->race + 1u ); } // moreinfo 3 start if ( ( client->UOExpansionFlag & Network::AOS ) ) { msg->WriteFlipped( chr->skillstatcap().statcap ); auto follow_value = chr->followers(); msg->Write( follow_value.followers ); msg->Write( follow_value.followers_max ); // moreinfo 4 start s16 value = chr->fire_resist().sum(); if ( chr->has_fire_resist_cap() && !ignore_caps ) { auto cap = chr->fire_resist_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); value = chr->cold_resist().sum(); if ( chr->has_cold_resist_cap() && !ignore_caps ) { auto cap = chr->cold_resist_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); value = chr->poison_resist().sum(); if ( chr->has_poison_resist_cap() && !ignore_caps ) { auto cap = chr->poison_resist_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); value = chr->energy_resist().sum(); if ( chr->has_energy_resist_cap() && !ignore_caps ) { auto cap = chr->energy_resist_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); msg->WriteFlipped( static_cast( chr->luck().sum() ) ); msg->WriteFlipped( chr->min_weapon_damage() ); msg->WriteFlipped( chr->max_weapon_damage() ); msg->WriteFlipped( chr->tithing() ); } // Add the new entries as 0's for now if ( client->ClientType & Network::CLIENTTYPE_70300 ) { // msg->offset += 30; msg->WriteFlipped( static_cast( chr->physical_resist_cap().sum() ) ); // Physical resist cap msg->WriteFlipped( static_cast( chr->fire_resist_cap().sum() ) ); // Fire resist cap msg->WriteFlipped( static_cast( chr->cold_resist_cap().sum() ) ); // Cold resist cap msg->WriteFlipped( static_cast( chr->poison_resist_cap().sum() ) ); // Poison resist cap msg->WriteFlipped( static_cast( chr->energy_resist_cap().sum() ) ); // Energy resist cap s16 value = chr->defence_increase().sum(); if ( chr->has_defence_increase_cap() && !ignore_caps ) { auto cap = chr->defence_increase_cap().sum(); value = std::min( cap, value ); } msg->WriteFlipped( static_cast( ( value < 0 ) ? ( 0x10000 + value ) : value ) ); // Defense chance increase msg->WriteFlipped( static_cast( chr->defence_increase_cap().sum() ) ); // Defense chance cap increase msg->WriteFlipped( static_cast( chr->hit_chance().sum() ) ); // Hit chance increase msg->WriteFlipped( static_cast( chr->swing_speed_increase().sum() ) ); // swing_speed_increase msg->offset += 2; // damage_increase msg->WriteFlipped( static_cast( chr->lower_reagent_cost().sum() ) ); // Lower reagent cost msg->WriteFlipped( static_cast( chr->spell_damage_increase().sum() ) ); // Spell damage increase msg->WriteFlipped( static_cast( chr->faster_cast_recovery().sum() ) ); // Faster cast recovery msg->WriteFlipped( static_cast( chr->faster_casting().sum() ) ); // Faster casting msg->WriteFlipped( static_cast( chr->lower_mana_cost().sum() ) ); // Lower mana cost } u16 len = msg->offset; msg->offset = 1; msg->WriteFlipped( len ); msg.Send( client, len ); if ( settingsManager.ssopt.send_stat_locks ) send_stat_locks( client, chr ); } void send_stat_locks( Network::Client* client, Mobile::Character* chr ) { if ( client->getversiondetail().major < 3 ) // only in AOS, I think return; u8 lockbit = 0; lockbit |= chr->attribute( networkManager.uoclient_general.strength.id ).lock() << 4; // XX SS DD II (2 bits for each lock) lockbit |= chr->attribute( networkManager.uoclient_general.dexterity.id ).lock() << 2; lockbit |= chr->attribute( networkManager.uoclient_general.intelligence.id ).lock(); PacketOut msg; msg->WriteFlipped( 12u ); msg->offset += 2; // sub msg->Write( 0x02u ); // 2D Client = 0x02, KR = 0x05 msg->Write( chr->serial_ext ); msg->offset++; // unk msg->Write( lockbit ); msg.Send( client ); } void send_short_statmsg( Network::Client* client, Mobile::Character* chr ) { PacketOut msg; msg->offset += 2; // msglen msg->Write( chr->serial_ext ); msg->Write( chr->name().c_str(), 30, false ); if ( networkManager.uoclient_general.hits.any ) { msg->WriteFlipped( static_cast( chr->vital( networkManager.uoclient_general.hits.id ).current_thousands() ) ); msg->WriteFlipped( 1000u ); // max_hits } else { msg->WriteFlipped( 0u ); // hits msg->WriteFlipped( 0u ); // max_hits } msg->Write( client->chr->can_rename( chr ) ? 0xFFu : 0u ); msg->Write( 0u ); // moreinfo u16 len = msg->offset; msg->offset = 1; msg->WriteFlipped( len ); msg.Send( client, len ); } void send_update_hits_to_inrange( Mobile::Character* chr ) { PacketOut msg; msg->Write( chr->serial_ext ); if ( networkManager.uoclient_general.hits.any ) { int h = chr->vital( networkManager.uoclient_general.hits.id ).current_ones(); if ( h > 0xFFFF ) h = 0xFFFF; int mh = chr->vital( networkManager.uoclient_general.hits.id ).maximum_ones(); if ( mh > 0xFFFF ) mh = 0xFFFF; msg->WriteFlipped( static_cast( mh ) ); msg->WriteFlipped( static_cast( h ) ); // Send proper data to self (if we exist?) if ( chr->client && chr->client->ready ) msg.Send( chr->client ); // To stop "HP snooping"... msg->offset = 5; msg->WriteFlipped( 1000u ); msg->WriteFlipped( static_cast( h * 1000 / mh ) ); } else { msg->offset += 4; // hits,maxhits=0 if ( chr->client && chr->client->ready ) msg.Send( chr->client ); } // Exclude self... otherwise their status-window shows 1000 hp!! >_< transmit_to_others_inrange( chr, &msg->buffer, msg->offset ); } } // namespace Core } // namespace Pol