• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 25853153562

14 May 2026 09:41AM UTC coverage: 60.906%. Remained the same
25853153562

push

github

web-flow
fixed problem when sending vitals bigger then 0xffff to other clients (#877)

* fixed problem when sending vitals bigger then 0xffff to other clients.
The percent value was calculated based on the already capped values

* directly use the correct type

* docs

1 of 24 new or added lines in 1 file covered. (4.17%)

2 existing lines in 2 files now uncovered.

44604 of 73234 relevant lines covered (60.91%)

515568.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.86
/pol-core/pol/statmsg.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2006/05/23 Shinigami: send_full_statmsg() updated to support Elfs
5
 * - 2009/07/23 MuadDib:   updates for new Enum::Packet Out ID
6
 * - 2009/08/09 MuadDib:   Re factor of Packet 0x25, 0x11 for naming convention
7
 * - 2009/09/06 Turley:    Changed Version checks to bitfield client->ClientType
8
 * - 2009/12/02 Turley:    fixed 0x11 packet (race flag)
9
 */
10

11

12
#include "statmsg.h"
13

14
#include "../clib/clib.h"
15
#include "../clib/rawtypes.h"
16
#include "globals/network.h"
17
#include "globals/settings.h"
18
#include "mobile/charactr.h"
19
#include "network/client.h"
20
#include "network/packethelper.h"
21
#include "network/packets.h"
22
#include "ufunc.h"
23
#include "uoclient.h"
24

25

26
namespace Pol::Core
27
{
28
using namespace Network::PktHelper;
29

30
void send_full_statmsg( Network::Client* client, Mobile::Character* chr )
81✔
31
{
32
  PacketOut<Network::PktOut_11> msg;
81✔
33
  msg->offset += 2;  // msglen
81✔
34
  msg->Write<u32>( chr->serial_ext );
81✔
35
  msg->Write( Clib::strUtf8ToCp1252( chr->name() ).c_str(), 30, false );
81✔
36
  bool ignore_caps = Core::settingsManager.ssopt.core_ignores_defence_caps;
81✔
37
  if ( networkManager.uoclient_general.hits.any )
81✔
38
  {
39
    auto v = Clib::clamp_convert<u16>(
81✔
40
        chr->vital( networkManager.uoclient_general.hits.id ).current_ones() );
81✔
41
    msg->WriteFlipped<u16>( v );  // hits
81✔
42
    v = Clib::clamp_convert<u16>(
81✔
43
        chr->vital( networkManager.uoclient_general.hits.id ).maximum_ones() );
81✔
44
    msg->WriteFlipped<u16>( v );  // max_hits
81✔
45
  }
46
  else
47
  {
NEW
48
    msg->WriteFlipped<u16>( 0_u16 );  // hits
×
NEW
49
    msg->WriteFlipped<u16>( 0_u16 );  // max_hits
×
50
  }
51
  msg->Write<u8>( 0_u8 );  // (client->chr->can_rename( chr ) ? 0xFF : 0);
81✔
52

53
  u8 type = 1u;  // Set to oldschool statbar info.
81✔
54
  if ( client->ClientType & Network::CLIENTTYPE_70300 )
81✔
55
    type = 6u;  // New entries for classic client
×
56
  else if ( client->acctSupports( Plib::ExpansionVersion::ML ) &&
81✔
57
            ( client->ClientType & Network::CLIENTTYPE_5000 ) )
×
58
    type = 5u;  // Set to ML level
×
59
  else if ( client->acctSupports( Plib::ExpansionVersion::AOS ) )
81✔
60
    type = 4u;  // Set to AOS level statbar for full info
81✔
61
  msg->Write<u8>( type );
81✔
62

63
  // if (chr->race == Plib::RACE_ELF)
64
  //  msg->Write(static_cast<u8>(chr->gender | FLAG_RACE));
65
  // else
66
  msg->Write<u8>( chr->gender );  // GENDER_MALE or GENDER_FEMALE (see ../plib/uconst.h)
81✔
67

68
  if ( networkManager.uoclient_general.strength.any )
81✔
69
  {
70
    auto v = Clib::clamp_convert<u16>(
81✔
71
        chr->attribute( networkManager.uoclient_general.strength.id ).effective() );
81✔
72
    msg->WriteFlipped<u16>( v );
81✔
73
  }
74
  else
NEW
75
    msg->WriteFlipped<u16>( 0_u16 );
×
76

77
  if ( networkManager.uoclient_general.dexterity.any )
81✔
78
  {
79
    auto v = Clib::clamp_convert<u16>(
81✔
80
        chr->attribute( networkManager.uoclient_general.dexterity.id ).effective() );
81✔
81
    msg->WriteFlipped<u16>( v );
81✔
82
  }
83
  else
NEW
84
    msg->WriteFlipped<u16>( 0_u16 );
×
85

86
  if ( networkManager.uoclient_general.intelligence.any )
81✔
87
  {
88
    auto v = Clib::clamp_convert<u16>(
81✔
89
        chr->attribute( networkManager.uoclient_general.intelligence.id ).effective() );
81✔
90
    msg->WriteFlipped<u16>( v );
81✔
91
  }
92
  else
NEW
93
    msg->WriteFlipped<u16>( 0_u16 );
×
94

95
  if ( networkManager.uoclient_general.stamina.any )
81✔
96
  {
97
    auto v = Clib::clamp_convert<u16>(
81✔
98
        chr->vital( networkManager.uoclient_general.stamina.id ).current_ones() );
81✔
99
    msg->WriteFlipped<u16>( v );
81✔
100

101
    v = Clib::clamp_convert<u16>(
81✔
102
        chr->vital( networkManager.uoclient_general.stamina.id ).maximum_ones() );
81✔
103
    msg->WriteFlipped<u16>( v );
81✔
104
  }
105
  else
106
  {
NEW
107
    msg->WriteFlipped<u16>( 0_u16 );
×
NEW
108
    msg->WriteFlipped<u16>( 0_u16 );
×
109
  }
110

111
  if ( networkManager.uoclient_general.mana.any )
81✔
112
  {
113
    auto v = Clib::clamp_convert<u16>(
81✔
114
        chr->vital( networkManager.uoclient_general.mana.id ).current_ones() );
81✔
115
    msg->WriteFlipped<u16>( v );
81✔
116

117
    v = Clib::clamp_convert<u16>(
81✔
118
        chr->vital( networkManager.uoclient_general.mana.id ).maximum_ones() );
81✔
119
    msg->WriteFlipped<u16>( v );
81✔
120
  }
121
  else
122
  {
NEW
123
    msg->WriteFlipped<u16>( 0_u16 );
×
NEW
124
    msg->WriteFlipped<u16>( 0_u16 );
×
125
  }
126

127
  msg->WriteFlipped<u32>( chr->gold_carried() );
81✔
128
  // Adjusted to work with Physical Resist if AOS client, and AOS Resistances enabled.
129
  if ( client->acctSupports( Plib::ExpansionVersion::AOS ) && client->aosresist )
81✔
130
  {
131
    s16 value = chr->physical_resist().sum();
×
132
    if ( chr->has_physical_resist_cap() && !ignore_caps )
×
133
    {
134
      auto cap = chr->physical_resist_cap().sum();
×
135
      value = std::min( cap, value );
×
136
    }
137
    msg->WriteFlipped<s16>( value );
×
138
  }
139
  else
140
    msg->WriteFlipped<u16>( chr->ar() );
81✔
141

142
  auto weight = Clib::clamp_convert<u16>( chr->weight() );
81✔
143
  msg->WriteFlipped<u16>( weight );
81✔
144

145
  // moreinfo 5
146
  if ( type >= 5 )
81✔
147
  {
148
    msg->WriteFlipped<u16>( chr->carrying_capacity() );
×
149
    msg->Write<u8>( chr->race + 1u );
×
150
  }
151

152
  // moreinfo 3 start
153
  if ( type >= 3 )
81✔
154
  {
155
    msg->WriteFlipped<s16>( chr->skillstatcap().statcap );
81✔
156
    auto follow_value = chr->followers();
81✔
157
    msg->Write<s8>( follow_value.followers );
81✔
158
    msg->Write<s8>( follow_value.followers_max );
81✔
159
    // moreinfo 4 start
160
    s16 value = chr->fire_resist().sum();
81✔
161
    if ( chr->has_fire_resist_cap() && !ignore_caps )
81✔
162
    {
163
      auto cap = chr->fire_resist_cap().sum();
×
164
      value = std::min( cap, value );
×
165
    }
166
    msg->WriteFlipped<s16>( value );
81✔
167
    value = chr->cold_resist().sum();
81✔
168
    if ( chr->has_cold_resist_cap() && !ignore_caps )
81✔
169
    {
170
      auto cap = chr->cold_resist_cap().sum();
×
171
      value = std::min( cap, value );
×
172
    }
173
    msg->WriteFlipped<s16>( value );
81✔
174
    value = chr->poison_resist().sum();
81✔
175
    if ( chr->has_poison_resist_cap() && !ignore_caps )
81✔
176
    {
177
      auto cap = chr->poison_resist_cap().sum();
×
178
      value = std::min( cap, value );
×
179
    }
180
    msg->WriteFlipped<s16>( value );
81✔
181
    value = chr->energy_resist().sum();
81✔
182
    if ( chr->has_energy_resist_cap() && !ignore_caps )
81✔
183
    {
184
      auto cap = chr->energy_resist_cap().sum();
×
185
      value = std::min( cap, value );
×
186
    }
187
    msg->WriteFlipped<s16>( value );
81✔
188
    msg->WriteFlipped<u16>( static_cast<u16>( chr->luck().sum() ) );
81✔
189

190
    msg->WriteFlipped<u16>( chr->min_weapon_damage() );
81✔
191
    msg->WriteFlipped<u16>( chr->max_weapon_damage() );
81✔
192
    msg->WriteFlipped<s32>( chr->tithing() );
81✔
193
  }
194

195
  if ( type >= 6 )
81✔
196
  {
197
    msg->WriteFlipped<u16>(
×
198
        static_cast<u16>( chr->physical_resist_cap().sum() ) );  // Physical resist cap
×
199
    msg->WriteFlipped<u16>( static_cast<u16>( chr->fire_resist_cap().sum() ) );  // Fire resist cap
×
200
    msg->WriteFlipped<u16>( static_cast<u16>( chr->cold_resist_cap().sum() ) );  // Cold resist cap
×
201
    msg->WriteFlipped<u16>(
×
202
        static_cast<u16>( chr->poison_resist_cap().sum() ) );  // Poison resist cap
×
203
    msg->WriteFlipped<u16>(
×
204
        static_cast<u16>( chr->energy_resist_cap().sum() ) );  // Energy resist cap
×
205
    s16 value = chr->defence_increase().sum();
×
206
    if ( chr->has_defence_increase_cap() && !ignore_caps )
×
207
    {
208
      auto cap = chr->defence_increase_cap().sum();
×
209
      value = std::min( cap, value );
×
210
    }
211
    msg->WriteFlipped<s16>( value );  // Defense chance increase
×
212
    msg->WriteFlipped<u16>(
×
213
        static_cast<u16>( chr->defence_increase_cap().sum() ) );  // Defense chance cap increase
×
214
    msg->WriteFlipped<u16>( static_cast<u16>( chr->hit_chance().sum() ) );  // Hit chance increase
×
215
    msg->WriteFlipped<u16>(
×
216
        static_cast<u16>( chr->swing_speed_increase().sum() ) );  // swing_speed_increase
×
217
    msg->offset += 2;                                             // damage_increase
×
218
    msg->WriteFlipped<u16>(
×
219
        static_cast<u16>( chr->lower_reagent_cost().sum() ) );  // Lower reagent cost
×
220
    msg->WriteFlipped<u16>(
×
221
        static_cast<u16>( chr->spell_damage_increase().sum() ) );  // Spell damage increase
×
222
    msg->WriteFlipped<u16>(
×
223
        static_cast<u16>( chr->faster_cast_recovery().sum() ) );  // Faster cast recovery
×
224
    msg->WriteFlipped<u16>( static_cast<u16>( chr->faster_casting().sum() ) );   // Faster casting
×
225
    msg->WriteFlipped<u16>( static_cast<u16>( chr->lower_mana_cost().sum() ) );  // Lower mana cost
×
226
  }
227

228
  u16 len = msg->offset;
81✔
229

230
  msg->offset = 1;
81✔
231
  msg->WriteFlipped<u16>( len );
81✔
232
  msg.Send( client, len );
81✔
233

234
  if ( settingsManager.ssopt.send_stat_locks )
81✔
235
    send_stat_locks( client, chr );
×
236
}
81✔
237

238
void send_stat_locks( Network::Client* client, Mobile::Character* chr )
×
239
{
240
  if ( client->getversiondetail().major < 3 )  // only in AOS, I think
×
241
    return;
×
242

243
  u8 lockbit = 0;
×
244

245
  lockbit |= chr->attribute( networkManager.uoclient_general.strength.id ).lock()
×
246
             << 4;  // XX SS DD II (2 bits for each lock)
×
247
  lockbit |= chr->attribute( networkManager.uoclient_general.dexterity.id ).lock() << 2;
×
248
  lockbit |= chr->attribute( networkManager.uoclient_general.intelligence.id ).lock();
×
249

250
  PacketOut<Network::PktOut_BF_Sub19> msg;
×
NEW
251
  msg->WriteFlipped<u16>( 12_u16 );
×
NEW
252
  msg->offset += 2;           // sub
×
NEW
253
  msg->Write<u8>( 0x02_u8 );  // 2D Client = 0x02, KR = 0x05
×
254
  msg->Write<u32>( chr->serial_ext );
×
255
  msg->offset++;  // unk
×
256
  msg->Write<u8>( lockbit );
×
257
  msg.Send( client );
×
258
}
×
259

260
void send_short_statmsg( Network::Client* client, Mobile::Character* chr )
×
261
{
262
  PacketOut<Network::PktOut_11> msg;
×
263
  msg->offset += 2;  // msglen
×
264
  msg->Write<u32>( chr->serial_ext );
×
265
  msg->Write( Clib::strUtf8ToCp1252( chr->name() ).c_str(), 30, false );
×
266

267
  if ( networkManager.uoclient_general.hits.any )
×
268
  {
269
    msg->WriteFlipped<u16>( Clib::clamp_convert<u16>(
×
270
        chr->vital( networkManager.uoclient_general.hits.id ).current_thousands() ) );
×
NEW
271
    msg->WriteFlipped<u16>( 1000_u16 );  // max_hits
×
272
  }
273
  else
274
  {
NEW
275
    msg->WriteFlipped<u16>( 0_u16 );  // hits
×
NEW
276
    msg->WriteFlipped<u16>( 0_u16 );  // max_hits
×
277
  }
NEW
278
  msg->Write<u8>( client->chr->can_rename( chr ) ? 0xFF_u8 : 0_u8 );
×
NEW
279
  msg->Write<u8>( 0_u8 );  // moreinfo
×
280

281
  u16 len = msg->offset;
×
282
  msg->offset = 1;
×
283
  msg->WriteFlipped<u16>( len );
×
284

285
  msg.Send( client, len );
×
286
}
×
287

288
void send_update_hits_to_inrange( Mobile::Character* chr )
×
289
{
290
  PacketOut<Network::PktOut_A1> msg;
×
291
  msg->Write<u32>( chr->serial_ext );
×
292

293
  if ( networkManager.uoclient_general.hits.any )
×
294
  {
NEW
295
    auto h = chr->vital( networkManager.uoclient_general.hits.id ).current_ones();
×
NEW
296
    auto mh = chr->vital( networkManager.uoclient_general.hits.id ).maximum_ones();
×
297
    // Send proper data to self (if we exist?)
298
    if ( chr->client && chr->client->ready )
×
299
    {
NEW
300
      msg->WriteFlipped<u16>( Clib::clamp_convert<u16>( mh ) );
×
NEW
301
      msg->WriteFlipped<u16>( Clib::clamp_convert<u16>( h ) );
×
302

UNCOV
303
      msg.Send( chr->client );
×
NEW
304
      msg->offset = 5;
×
305
    }
306

307
    // To stop "HP snooping"...
NEW
308
    msg->WriteFlipped<u16>( 1000_u16 );
×
309
    msg->WriteFlipped<u16>( Clib::clamp_convert<u16>( h * 1000 / mh ) );
×
310
  }
311
  else
312
  {
313
    msg->offset += 4;  // hits,maxhits=0
×
314
    if ( chr->client && chr->client->ready )
×
315
      msg.Send( chr->client );
×
316
  }
317

318
  // Exclude self... otherwise their status-window shows 1000 hp!! >_<
319
  transmit_to_others_inrange( chr, &msg->buffer, msg->offset );
×
320
}
×
321
}  // namespace Pol::Core
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc