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

polserver / polserver / 21541532363

31 Jan 2026 08:14AM UTC coverage: 60.532% (+0.03%) from 60.507%
21541532363

push

github

web-flow
Tidy modernize for loops (#862)

* trigger loop convert

* Automated clang-tidy change: modernize-loop-convert

* fixed refactor

* Automated clang-tidy change: modernize-loop-convert

* compile

* first look through

* fixes and start to use a few ranges

* revert autogenerated file

* compilation fix

* second pass

* renamed loop variable

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>

164 of 447 new or added lines in 61 files covered. (36.69%)

6 existing lines in 5 files now uncovered.

44377 of 73312 relevant lines covered (60.53%)

499857.83 hits per line

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

34.85
/pol-core/pol/speech.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2009/07/23 MuadDib:   updates for new Enum::Packet Out ID
5
 * - 2009/08/01 MuadDib:   Rewrote where needed to do away with TEXTDEF struct useage. Pointless.
6
 * - 2009/08/25 Shinigami: STLport-5.2.1 fix: buffer not used
7
 * - 2009/09/03 MuadDib:   Relocation of account related cpp/h
8
 * - 2009/10/14 Turley:    new priv canbeheardasghost
9
 * - 2009/10/14 Turley:    Added char.deaf() methods & char.deafened member
10
 */
11

12

13
#include <cctype>
14
#include <cstddef>
15
#include <iostream>
16
#include <memory>
17
#include <string>
18

19
#include "../bscript/bobject.h"
20
#include "../bscript/impstr.h"
21
#include "../clib/clib_endian.h"
22
#include "../clib/logfacility.h"
23
#include "../clib/random.h"
24
#include "../clib/rawtypes.h"
25
#include "../plib/systemstate.h"
26
#include "globals/settings.h"
27
#include "globals/uvars.h"
28
#include "guilds.h"
29
#include "listenpt.h"
30
#include "mkscrobj.h"
31
#include "mobile/charactr.h"
32
#include "mobile/npc.h"
33
#include "network/client.h"
34
#include "network/packethelper.h"
35
#include "network/packets.h"
36
#include "network/pktdef.h"
37
#include "network/pktin.h"
38
#include "syshook.h"
39
#include "textcmd.h"
40
#include "tildecmd.h"
41
#include "ufunc.h"
42
#include "ufuncstd.h"
43
#include "uworld.h"
44

45

46
namespace Pol::Core
47
{
48
void handle_processed_speech( Network::Client* client, const std::string& text, u8 type, u16 color,
×
49
                              u16 font )
50
{
51
  if ( text.empty() )
×
52
    return;
×
53

54
  std::string s_text( text );
×
55
  Clib::sanitizeUnicodeWithIso( &s_text );  // use original text for other clients
×
56
  Mobile::Character* chr = client->chr;
×
57

58
  // validate text color
59
  u16 textcol = cfBEu16( color );
×
60
  if ( textcol < 2 || textcol > 1001 )
×
61
  {
62
    textcol = 1001;
×
63
  }
64
  chr->last_textcolor( textcol );
×
65

66
  if ( s_text[0] == '.' || s_text[0] == '=' )
×
67
  {
68
    if ( !process_command( client, s_text ) )
×
69
      send_sysmessage( client, std::string( "Unknown command: " ) + text );
×
70
    return;
×
71
  }
72

73
  if ( s_text[0] == '~' )
×
74
  {
75
    process_tildecommand( client, s_text );
×
76
    return;
×
77
  }
78

79
  if ( chr->squelched() )
×
80
    return;
×
81

82
  if ( chr->hidden() )
×
83
    chr->unhide();
×
84

85
  if ( Plib::systemstate.config.show_speech_colors )
×
86
  {
87
    INFO_PRINTLN( "{} speaking w/ color {:#x}", chr->name(), cfBEu16( color ) );
×
88
  }
89
  std::string convertedText = Clib::strUtf8ToCp1252( text );
×
90
  u16 textlen = static_cast<u16>( convertedText.size() + 1 );
×
91
  if ( textlen > SPEECH_MAX_LEN + 1 )
×
92
    textlen = SPEECH_MAX_LEN + 1;
×
93

94
  Network::PktHelper::PacketOut<Network::PktOut_1C> talkmsg;
×
95
  talkmsg->offset += 2;
×
96
  talkmsg->Write<u32>( chr->serial_ext );
×
97
  talkmsg->WriteFlipped<u16>( chr->graphic );
×
98
  talkmsg->Write<u8>( type );  // FIXME authorize
×
99
  talkmsg->WriteFlipped<u16>( textcol );
×
100
  talkmsg->WriteFlipped<u16>( font );
×
101
  talkmsg->Write( Clib::strUtf8ToCp1252( chr->name() ).c_str(), 30 );
×
102
  talkmsg->Write( convertedText.c_str(), textlen );
×
103
  u16 len = talkmsg->offset;
×
104
  talkmsg->offset = 1;
×
105
  talkmsg->WriteFlipped<u16>( len );
×
106
  talkmsg.Send( client, len );
×
107

108
  Network::PktHelper::PacketOut<Network::PktOut_1C> ghostmsg;
×
109
  if ( chr->dead() && !chr->can_be_heard_as_ghost() )
×
110
  {
111
    memcpy( &ghostmsg->buffer, &talkmsg->buffer, sizeof ghostmsg->buffer );
×
112
    ghostmsg->offset = 44;
×
113
    char* t = &ghostmsg->buffer[ghostmsg->offset];
×
114
    while ( ghostmsg->offset < len )
×
115
    {
116
      if ( !isspace( *t ) )
×
117
      {
118
        if ( Clib::random_int( 3 ) == 0 )
×
119
          *t = 'o';
×
120
        else
121
          *t = 'O';
×
122
      }
123
      ++t;
×
124
      ghostmsg->offset++;
×
125
    }
126
  }
127
  // send to those nearby
128
  u16 range;
129
  if ( type == Plib::TEXTTYPE_WHISPER )
×
130
    range = Core::settingsManager.ssopt.whisper_range;
×
131
  else if ( type == Plib::TEXTTYPE_YELL )
×
132
    range = Core::settingsManager.ssopt.yell_range;
×
133
  else
134
    range = Core::settingsManager.ssopt.speech_range;
×
135
  Core::WorldIterator<Core::OnlinePlayerFilter>::InRange(
×
136
      chr, range,
137
      [&]( Mobile::Character* other_chr )
×
138
      {
139
        Network::Client* client2 = other_chr->client;
×
140
        if ( client == client2 )
×
141
          return;
×
142
        if ( !other_chr->is_visible_to_me( chr, /*check_range*/ false ) )
×
143
          return;
×
144
        if ( other_chr->deafened() )
×
145
          return;
×
146

147
        if ( !chr->dead() || other_chr->dead() || other_chr->can_hearghosts() ||
×
148
             chr->can_be_heard_as_ghost() )
×
149
        {
150
          talkmsg.Send( client2, len );
×
151
        }
152
        else
153
        {
154
          ghostmsg.Send( client2, len );
×
155
        }
156
      } );
157

158
  if ( !chr->dead() )
×
159
  {
160
    Core::WorldIterator<Core::NPCFilter>::InRange( chr, range,
×
161
                                                   [&]( Mobile::Character* otherchr )
×
162
                                                   {
163
                                                     Mobile::NPC* npc =
×
164
                                                         static_cast<Mobile::NPC*>( otherchr );
165
                                                     npc->on_pc_spoke( chr, s_text, type );
×
166
                                                   } );
×
167
  }
168
  else
169
  {
170
    Core::WorldIterator<Core::NPCFilter>::InRange( chr, range,
×
171
                                                   [&]( Mobile::Character* otherchr )
×
172
                                                   {
173
                                                     Mobile::NPC* npc =
×
174
                                                         static_cast<Mobile::NPC*>( otherchr );
175
                                                     npc->on_ghost_pc_spoke( chr, s_text, type );
×
176
                                                   } );
×
177
  }
178

179
  ListenPoint::sayto_listening_points( client->chr, s_text, type );
×
180
}
×
181

182

183
void SpeechHandler( Network::Client* client, PKTIN_03* mymsg )
×
184
{
185
  int intextlen = cfBEu16( mymsg->msglen ) - offsetof( PKTIN_03, text ) - 1;
×
186

187
  // Preprocess the text into a sanity-checked, printable form in text
188
  if ( intextlen < 0 )
×
189
    intextlen = 0;
×
190
  if ( intextlen > SPEECH_MAX_LEN )
×
191
    intextlen = SPEECH_MAX_LEN;  // ENHANCE: May want to log this
×
192

193
  std::string text;
×
194
  text.reserve( intextlen );
×
195
  for ( int i = 0; i < intextlen; i++ )
×
196
  {
197
    char ch = mymsg->text[i];
×
198

199
    if ( ch == 0 )
×
200
      break;
×
201
    if ( isprint( ch ) )
×
202
      text += ch;
×
203
    // ENHANCE: else report client data error? Just log?
204
  }
205
  handle_processed_speech( client, text, mymsg->type, mymsg->color, mymsg->font );
×
206
}
×
207

208
void SendUnicodeSpeech( Network::Client* client, PKTIN_AD* msgin, const std::string& text,
3✔
209
                        std::unique_ptr<Bscript::ObjArray> speechtokens )
210
{
211
  if ( text.empty() )
3✔
212
    return;
×
213
  // validate text color
214
  u16 textcol = cfBEu16( msgin->color );
3✔
215
  if ( textcol < 2 || textcol > 1001 )
3✔
216
  {
217
    // 3/8/2009 MuadDib Changed to default color instead of complain.
218
    textcol = 1001;
3✔
219
  }
220

221
  Mobile::Character* chr = client->chr;
3✔
222

223
  chr->last_textcolor( textcol );
3✔
224

225
  if ( text[0] == '.' || text[0] == '=' )
3✔
226
  {
227
    std::string lang( msgin->lang );
×
228
    if ( !process_command( client, text, lang ) )
×
229
    {
230
      std::string tmp( "Unknown command: " + text );
×
231
      send_sysmessage_unicode( client, tmp, lang );
×
232
    }
×
233
    return;
×
234
  }
×
235

236
  if ( text[0] == '~' )
3✔
237
  {
238
    process_tildecommand( client, text );
×
239
    return;
×
240
  }
241

242
  if ( chr->squelched() )
3✔
243
    return;
×
244

245
  if ( chr->hidden() )
3✔
246
    chr->unhide();
×
247

248
  if ( Plib::systemstate.config.show_speech_colors )
3✔
249
  {
250
    INFO_PRINTLN( "{} speaking w/ color {:#x}", chr->name(), cfBEu16( msgin->color ) );
×
251
  }
252

253
  Network::PktHelper::PacketOut<Network::PktOut_AE> ghostmsg;
3✔
254
  Network::PktHelper::PacketOut<Network::PktOut_AE> talkmsg;
3✔
255
  talkmsg->offset += 2;
3✔
256
  talkmsg->Write<u32>( chr->serial_ext );
3✔
257
  talkmsg->WriteFlipped<u16>( chr->graphic );
3✔
258
  talkmsg->Write<u8>( msgin->type );  // FIXME authorize
3✔
259
  talkmsg->WriteFlipped<u16>( textcol );
3✔
260
  talkmsg->WriteFlipped<u16>( msgin->font );
3✔
261
  talkmsg->Write( msgin->lang, 4 );
3✔
262
  talkmsg->Write( Clib::strUtf8ToCp1252( chr->name() ).c_str(), 30 );
3✔
263

264
  std::vector<u16> utf16 = Bscript::String::toUTF16( text );
3✔
265
  if ( utf16.size() > SPEECH_MAX_LEN )
3✔
266
    utf16.resize( SPEECH_MAX_LEN );
×
267
  talkmsg->WriteFlipped( utf16, true );
3✔
268
  u16 len = talkmsg->offset;
3✔
269
  talkmsg->offset = 1;
3✔
270
  talkmsg->WriteFlipped<u16>( len );
3✔
271

272

273
  if ( msgin->type == 0x0d )
3✔
274
  {
275
    auto thisguild = chr->guild();
×
276
    if ( settingsManager.ssopt.core_sends_guildmsgs && thisguild != nullptr )
×
277
    {
NEW
278
      for ( auto client2 : networkManager.clients )
×
279
      {
280
        if ( !client2->ready )
×
281
          continue;
×
282
        if ( thisguild->guildid() == client2->chr->guildid() )
×
283
          talkmsg.Send( client2, len );
×
284
      }
285
    }
286
  }
287
  else if ( msgin->type == 0x0e )
3✔
288
  {
289
    auto thisguild = chr->guild();
×
290
    if ( settingsManager.ssopt.core_sends_guildmsgs && thisguild != nullptr )
×
291
    {
NEW
292
      for ( auto client2 : networkManager.clients )
×
293
      {
294
        if ( !client2->ready )
×
295
          continue;
×
296
        auto otherguild = client2->chr->guild();
×
297
        if ( otherguild != nullptr )
×
298
        {
299
          if ( thisguild->guildid() == otherguild->guildid() ||
×
300
               ( thisguild->hasAlly( otherguild ) ) )
×
301
            talkmsg.Send( client2, len );
×
302
        }
303
      }
304
    }
305
  }
306
  else
307
  {
308
    talkmsg.Send( client, len );  // self
3✔
309
    if ( chr->dead() && !chr->can_be_heard_as_ghost() )
3✔
310
    {
311
      memcpy( &ghostmsg->buffer, &talkmsg->buffer, sizeof ghostmsg->buffer );
×
312

313
      ghostmsg->offset = 48;
×
314
      u16* t = ( (u16*)&ghostmsg->buffer[ghostmsg->offset] );
×
315
      while ( ghostmsg->offset < len - 2 )  // dont convert nullterm
×
316
      {
317
        wchar_t wch = ( *t );
×
318
        if ( !iswspace( wch ) )
×
319
        {
320
          if ( Clib::random_int( 3 ) == 0 )
×
321
            *t = ctBEu16( L'o' );
×
322
          else
323
            *t = ctBEu16( L'O' );
×
324
        }
325
        ++t;
×
326
        ghostmsg->offset += 2;
×
327
      }
328
    }
329
    // send to those nearby
330
    u16 range;
331
    if ( msgin->type == Plib::TEXTTYPE_WHISPER )
3✔
332
      range = Core::settingsManager.ssopt.whisper_range;
×
333
    else if ( msgin->type == Plib::TEXTTYPE_YELL )
3✔
334
      range = Core::settingsManager.ssopt.yell_range;
×
335
    else
336
      range = Core::settingsManager.ssopt.speech_range;
3✔
337
    Core::WorldIterator<Core::OnlinePlayerFilter>::InRange(
3✔
338
        chr, range,
339
        [&]( Mobile::Character* otherchr )
3✔
340
        {
341
          Network::Client* client2 = otherchr->client;
6✔
342
          if ( client == client2 )
6✔
343
            return;
3✔
344
          if ( !otherchr->is_visible_to_me( chr, /*check_range*/ false ) )
3✔
345
            return;
×
346
          if ( otherchr->deafened() )
3✔
347
            return;
×
348

349
          if ( !chr->dead() || otherchr->dead() || otherchr->can_hearghosts() ||
3✔
350
               chr->can_be_heard_as_ghost() )
×
351
          {
352
            talkmsg.Send( client2, len );
3✔
353
          }
354
          else
355
          {
356
            ghostmsg.Send( client2, len );
×
357
          }
358
        } );
359

360
    if ( !chr->dead() )
3✔
361
    {
362
      Core::WorldIterator<Core::NPCFilter>::InRange(
3✔
363
          chr, range,
364
          [&]( Mobile::Character* otherchr )
3✔
365
          {
366
            Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
2✔
367
            npc->on_pc_spoke( chr, text, msgin->type, msgin->lang, speechtokens.get() );
2✔
368
          } );
2✔
369
    }
370
    else
371
    {
372
      Core::WorldIterator<Core::NPCFilter>::InRange(
×
373
          chr, range,
374
          [&]( Mobile::Character* otherchr )
×
375
          {
376
            Mobile::NPC* npc = static_cast<Mobile::NPC*>( otherchr );
×
377
            npc->on_ghost_pc_spoke( chr, text, msgin->type, msgin->lang, speechtokens.get() );
×
378
          } );
×
379
    }
380
    ListenPoint::sayto_listening_points( client->chr, text, msgin->type, msgin->lang,
3✔
381
                                         speechtokens.get() );
382
  }
383
}
3✔
384
u16 Get12BitNumber( u8* thearray, u16 theindex )
6✔
385
{
386
  u16 theresult = 0;
6✔
387
  int thenibble = theindex * 3;
6✔
388
  int thebyte = thenibble / 2;
6✔
389
  if ( thenibble % 2 )
6✔
390
    theresult = cfBEu16( *( (u16*)( thearray + thebyte ) ) ) & 0x0FFF;
2✔
391
  else
392
    theresult = cfBEu16( *( (u16*)( thearray + thebyte ) ) ) >> 4;
4✔
393
  return theresult;
6✔
394
}
395

396
void UnicodeSpeechHandler( Network::Client* client, PKTIN_AD* msgin )
3✔
397
{
398
  u16 numtokens = 0;
3✔
399
  std::unique_ptr<Bscript::ObjArray> speechtokens( nullptr );
3✔
400
  std::string text;
3✔
401
  if ( msgin->type & 0xc0 )
3✔
402
  {
403
    numtokens = Get12BitNumber( (u8*)( msgin->wtext ), 0 );
2✔
404
    int wtextoffset = ( ( ( ( numtokens + 1 ) * 3 ) / 2 ) + ( ( numtokens + 1 ) % 2 ) );
2✔
405
    int bytemsglen = cfBEu16( msgin->msglen ) - wtextoffset - offsetof( Core::PKTIN_AD, wtext ) - 1;
2✔
406
    if ( bytemsglen < 0 )
2✔
407
      bytemsglen = 0;
×
408
    text = Bscript::String::fromUTF8( reinterpret_cast<const char*>( msgin->wtext ) + wtextoffset,
4✔
409
                                      bytemsglen );
2✔
410
  }
411
  else
412
  {
413
    int intextlen = ( cfBEu16( msgin->msglen ) - offsetof( Core::PKTIN_AD, wtext ) ) /
1✔
414
                        sizeof( msgin->wtext[0] ) -
1✔
415
                    1;
416
    if ( intextlen < 0 )
1✔
417
      intextlen = 0;
×
418
    text = Bscript::String::fromUTF16( msgin->wtext, intextlen, true );
1✔
419
  }
420
  //  SPEECH_MAX_LEN needs to be checked later
421

422
  if ( msgin->type & 0xc0 )
3✔
423
  {
424
    speechtokens = std::make_unique<Bscript::ObjArray>();
2✔
425
    for ( u16 j = 0; j < numtokens; j++ )
6✔
426
    {
427
      speechtokens->addElement(
8✔
428
          new Bscript::BLong( Get12BitNumber( (u8*)( msgin->wtext ), j + 1 ) ) );
4✔
429
    }
430
    if ( gamestate.system_hooks.speechmul_hook )
2✔
431
    {
432
      gamestate.system_hooks.speechmul_hook->call( make_mobileref( client->chr ),
×
433
                                                   new Bscript::ObjArray( *speechtokens.get() ),
×
434
                                                   new Bscript::String( text ) );
×
435
    }
436
    msgin->type &= ( ~0xC0 );  // Client won't accept C0 text type messages, so must set to 0
2✔
437
  }
438

439
  SendUnicodeSpeech( client, msgin, text, std::move( speechtokens ) );
3✔
440
}
3✔
441
}  // 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