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

polserver / polserver / 20658686229

02 Jan 2026 01:17PM UTC coverage: 60.283% (+0.01%) from 60.272%
20658686229

push

github

web-flow
cleanup code for statmsg (#836)

34 of 44 new or added lines in 1 file covered. (77.27%)

2 existing lines in 1 file now uncovered.

44281 of 73455 relevant lines covered (60.28%)

518588.62 hits per line

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

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

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

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

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

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

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

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

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

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

127
  msg->WriteFlipped<u32>( chr->gold_carried() );
90✔
128
  // Adjusted to work with Physical Resist if AOS client, and AOS Resistances enabled.
129
  if ( client->acctSupports( Plib::ExpansionVersion::AOS ) && client->aosresist )
90✔
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() );
90✔
141

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

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

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

195
  if ( type >= 6 )
90✔
196
  {
UNCOV
197
    msg->WriteFlipped<u16>(
×
UNCOV
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;
90✔
229

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

234
  if ( settingsManager.ssopt.send_stat_locks )
90✔
235
    send_stat_locks( client, chr );
×
236
}
90✔
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;
×
251
  msg->WriteFlipped<u16>( 12u );
×
252
  msg->offset += 2;         // sub
×
253
  msg->Write<u8>( 0x02u );  // 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
  {
NEW
269
    msg->WriteFlipped<u16>( Clib::clamp_convert<u16>(
×
270
        chr->vital( networkManager.uoclient_general.hits.id ).current_thousands() ) );
×
271
    msg->WriteFlipped<u16>( 1000u );  // max_hits
×
272
  }
273
  else
274
  {
275
    msg->WriteFlipped<u16>( 0u );  // hits
×
276
    msg->WriteFlipped<u16>( 0u );  // max_hits
×
277
  }
278
  msg->Write<u8>( client->chr->can_rename( chr ) ? 0xFFu : 0u );
×
279
  msg->Write<u8>( 0u );  // 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 = Clib::clamp_convert<u16>(
×
NEW
296
        chr->vital( networkManager.uoclient_general.hits.id ).current_ones() );
×
NEW
297
    auto mh = Clib::clamp_convert<u16>(
×
NEW
298
        chr->vital( networkManager.uoclient_general.hits.id ).maximum_ones() );
×
NEW
299
    msg->WriteFlipped<u16>( mh );
×
NEW
300
    msg->WriteFlipped<u16>( h );
×
301

302
    // Send proper data to self (if we exist?)
303
    if ( chr->client && chr->client->ready )
×
304
      msg.Send( chr->client );
×
305

306
    // To stop "HP snooping"...
307
    msg->offset = 5;
×
308
    msg->WriteFlipped<u16>( 1000u );
×
NEW
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