GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/actormanager.cpp Lines: 136 981 13.9 %
Date: 2019-08-19 Branches: 137 1424 9.6 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2019  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "actormanager.h"
24
25
#include "game.h"
26
#include "guild.h"
27
#include "configuration.h"
28
#include "settings.h"
29
30
#include "being/localplayer.h"
31
#include "being/playerrelations.h"
32
33
#include "gui/sdlinput.h"
34
#include "gui/viewport.h"
35
36
#include "gui/widgets/tabs/chat/chattab.h"
37
38
#include "gui/windows/equipmentwindow.h"
39
#include "gui/windows/socialwindow.h"
40
#include "gui/windows/questswindow.h"
41
42
#include "fs/files.h"
43
44
#include "input/inputmanager.h"
45
46
#include "utils/checkutils.h"
47
#include "utils/foreach.h"
48
#include "utils/mathutils.h"
49
#include "utils/gettext.h"
50
51
#include "net/beinghandler.h"
52
#include "net/charserverhandler.h"
53
#include "net/packetlimiter.h"
54
#include "net/playerhandler.h"
55
#include "net/serverfeatures.h"
56
57
#include "resources/chatobject.h"
58
#include "resources/iteminfo.h"
59
60
#include "resources/map/map.h"
61
62
#include "resources/db/itemdb.h"
63
64
#ifdef TMWA_SUPPORT
65
#include "being/playerinfo.h"
66
67
#include "gui/windows/chatwindow.h"
68
69
#include "net/net.h"
70
#endif  // TMWA_SUPPORT
71
72
#include "debug.h"
73
74
#define for_actors for (ActorSpritesConstIterator it = mActors.begin(), \
75
    it_fend = mActors.end(); it != it_fend; ++it)
76
77
#define for_actorsm for (ActorSpritesIterator it = mActors.begin(), \
78
    it_fend = mActors.end(); it != it_fend; ++it)
79
80
ActorManager *actorManager = nullptr;
81
82
class FindBeingFunctor final
83
{
84
    public:
85
        A_DEFAULT_COPY(FindBeingFunctor)
86
87
        bool operator() (const ActorSprite *const actor) const
88
        {
89
            if ((actor == nullptr)
90
                || actor->getType() == ActorType::FloorItem
91
                || actor->getType() == ActorType::Portal)
92
            {
93
                return false;
94
            }
95
            const Being *const b = static_cast<const Being *>(actor);
96
97
            const unsigned other_y = y
98
                + ((b->getType() == ActorType::Npc) ? 1 : 0);
99
            const Vector &pos = b->getPixelPositionF();
100
            // +++ probably here need use int positions and not float?
101
            // but for now correct int positions only in Being
102
            return CAST_U32(pos.x) / mapTileSize == x &&
103
                (CAST_U32(pos.y) / mapTileSize == y
104
                || CAST_U32(pos.y) / mapTileSize == other_y) &&
105
                b->isAlive() && (type == ActorType::Unknown
106
                || b->getType() == type);
107
        }
108
109
        uint16_t x, y;
110
        ActorTypeT type;
111
} beingActorFinder;
112
113
class FindBeingEqualFunctor final
114
{
115
    public:
116
        A_DEFAULT_COPY(FindBeingEqualFunctor)
117
118
        bool operator() (const Being *const being) const
119
        {
120
            if ((being == nullptr) || (findBeing == nullptr))
121
                return false;
122
            return being->getId() == findBeing->getId();
123
        }
124
125
        Being *findBeing;
126
} beingEqualActorFinder;
127
128
class SortBeingFunctor final
129
{
130
    public:
131
        A_DEFAULT_COPY(SortBeingFunctor)
132
133
        bool operator() (const Being *const being1,
134
                         const Being *const being2) const
135
        {
136
            if ((being1 == nullptr) || (being2 == nullptr))
137
                return false;
138
139
            if (priorityBeings != nullptr)
140
            {
141
                int w1 = defaultPriorityIndex;
142
                int w2 = defaultPriorityIndex;
143
                const StringIntMapCIter it1 = priorityBeings->find(
144
                    being1->getName());
145
                const StringIntMapCIter it2 = priorityBeings->find(
146
                    being2->getName());
147
                if (it1 != priorityBeings->end())
148
                    w1 = (*it1).second;
149
                if (it2 != priorityBeings->end())
150
                    w2 = (*it2).second;
151
152
                if (w1 != w2)
153
                    return w1 < w2;
154
            }
155
            if (being1->getDistance() != being2->getDistance())
156
            {
157
                if (specialDistance && being1->getDistance() <= 2
158
                    && being2->getDistance() <= attackRange
159
                    && being2->getDistance() > 2)
160
                {
161
                    return false;
162
                }
163
                else if (specialDistance && being2->getDistance() <= 2
164
                         && being1->getDistance() <= attackRange
165
                         && being1->getDistance() > 2)
166
                {
167
                    return true;
168
                }
169
                return being1->getDistance() < being2->getDistance();
170
            }
171
172
            const int d1 = abs(being1->getTileX() - x)
173
                + abs(being1->getTileY() - y);
174
            const int d2 = abs(being2->getTileX() - x)
175
                + abs(being2->getTileY() - y);
176
177
            if (d1 != d2)
178
                return d1 < d2;
179
            if (attackBeings != nullptr)
180
            {
181
                int w1 = defaultAttackIndex;
182
                int w2 = defaultAttackIndex;
183
                const StringIntMapCIter it1 = attackBeings->find(
184
                    being1->getName());
185
                const StringIntMapCIter it2 = attackBeings->find(
186
                    being2->getName());
187
                if (it1 != attackBeings->end())
188
                    w1 = (*it1).second;
189
                if (it2 != attackBeings->end())
190
                    w2 = (*it2).second;
191
192
                if (w1 != w2)
193
                    return w1 < w2;
194
            }
195
196
            return being1->getName() < being2->getName();
197
        }
198
        StringIntMap *attackBeings;
199
        StringIntMap *priorityBeings;
200
        int x;
201
        int y;
202
        int defaultAttackIndex;
203
        int defaultPriorityIndex;
204
        int attackRange;
205
        bool specialDistance;
206
} beingActorSorter;
207
208
5
ActorManager::ActorManager() :
209
    mActors(),
210
    mDeleteActors(),
211
    mActorsIdMap(),
212
    mIdName(),
213
    mBlockedBeings(),
214
    mChars(),
215
    mMap(nullptr),
216
#ifdef TMWA_SUPPORT
217
    mSpellHeal1(serverConfig.getValue("spellHeal1", "#lum")),
218
    mSpellHeal2(serverConfig.getValue("spellHeal2", "#inma")),
219
    mSpellItenplz(serverConfig.getValue("spellItenplz", "#itenplz")),
220
#endif  // TMWA_SUPPORT
221

20
    mTargetDeadPlayers(config.getBoolValue("targetDeadPlayers")),
222

20
    mTargetOnlyReachable(config.getBoolValue("targetOnlyReachable")),
223

20
    mCyclePlayers(config.getBoolValue("cyclePlayers")),
224

20
    mCycleMonsters(config.getBoolValue("cycleMonsters")),
225

20
    mCycleNPC(config.getBoolValue("cycleNPC")),
226

20
    mExtMouseTargeting(config.getBoolValue("extMouseTargeting")),
227

20
    mEnableIdCollecting(config.getBoolValue("enableIdCollecting")),
228
    mPriorityAttackMobs(),
229
    mPriorityAttackMobsSet(),
230
    mPriorityAttackMobsMap(),
231
    mAttackMobs(),
232
    mAttackMobsSet(),
233
    mAttackMobsMap(),
234
    mIgnoreAttackMobs(),
235
    mIgnoreAttackMobsSet(),
236
    mPickupItems(),
237
    mPickupItemsSet(),
238
    mPickupItemsMap(),
239
    mIgnorePickupItems(),
240




235
    mIgnorePickupItemsSet()
241
{
242

20
    config.addListener("targetDeadPlayers", this);
243

20
    config.addListener("targetOnlyReachable", this);
244

20
    config.addListener("cyclePlayers", this);
245

20
    config.addListener("cycleMonsters", this);
246

20
    config.addListener("cycleNPC", this);
247

20
    config.addListener("extMouseTargeting", this);
248

20
    config.addListener("showBadges", this);
249

20
    config.addListener("enableIdCollecting", this);
250

20
    config.addListener("visiblenamespos", this);
251
252
5
    loadAttackList();
253
5
}
254
255
125
ActorManager::~ActorManager()
256
{
257
5
    config.removeListeners(this);
258
    CHECKLISTENERS
259
5
    storeAttackList();
260
5
    clear();
261
10
}
262
263
void ActorManager::setMap(Map *const map)
264
{
265
    mMap = map;
266
267
    if (localPlayer != nullptr)
268
        localPlayer->setMap(map);
269
}
270
271
void ActorManager::setPlayer(LocalPlayer *const player)
272
{
273
    localPlayer = player;
274
    mActors.insert(player);
275
    mActorsIdMap[player->getId()] = player;
276
    if (socialWindow != nullptr)
277
        socialWindow->updateAttackFilter();
278
    if (socialWindow != nullptr)
279
        socialWindow->updatePickupFilter();
280
}
281
282
Being *ActorManager::createBeing(const BeingId id,
283
                                 const ActorTypeT type,
284
                                 const BeingTypeId subtype)
285
{
286
    Being *const being = Being::createBeing(id,
287
        type,
288
        subtype,
289
        mMap);
290
291
    mActors.insert(being);
292
293
    mActorsIdMap[being->getId()] = being;
294
295
    switch (type)
296
    {
297
        case ActorType::Player:
298
        case ActorType::Mercenary:
299
        case ActorType::Pet:
300
        case ActorType::Homunculus:
301
        case ActorType::Npc:
302
            being->updateFromCache();
303
            if (beingHandler != nullptr)
304
                beingHandler->requestNameById(id);
305
            if (localPlayer != nullptr)
306
                localPlayer->checkNewName(being);
307
            break;
308
        case ActorType::Monster:
309
#ifdef TMWA_SUPPORT
310
            if (Net::getNetworkType() != ServerType::TMWATHENA)
311
#endif  // TMWA_SUPPORT
312
            {
313
                beingHandler->requestNameById(id);
314
            }
315
            break;
316
        case ActorType::Portal:
317
            if ((beingHandler != nullptr) &&
318
                (serverFeatures != nullptr) &&
319
                serverFeatures->haveServerWarpNames())
320
            {
321
                beingHandler->requestNameById(id);
322
            }
323
            break;
324
        case ActorType::Elemental:
325
            if (beingHandler != nullptr)
326
                beingHandler->requestNameById(id);
327
            break;
328
        case ActorType::SkillUnit:
329
            break;
330
        default:
331
        case ActorType::FloorItem:
332
        case ActorType::Avatar:
333
        case ActorType::Unknown:
334
            reportAlways("CreateBeing for unknown type %d", CAST_S32(type))
335
            break;
336
    }
337
338
    if (type == ActorType::Player)
339
    {
340
        if (socialWindow != nullptr)
341
            socialWindow->updateActiveList();
342
    }
343
    else if (type == ActorType::Npc)
344
    {
345
        if (questsWindow != nullptr)
346
            questsWindow->addEffect(being);
347
    }
348
    return being;
349
}
350
351
FloorItem *ActorManager::createItem(const BeingId id,
352
                                    const int itemId,
353
                                    const int x, const int y,
354
                                    const ItemTypeT itemType,
355
                                    const int amount,
356
                                    const int refine,
357
                                    const ItemColor color,
358
                                    const Identified identified,
359
                                    const Damaged damaged,
360
                                    const int subX, const int subY,
361
                                    const int *const cards)
362
{
363
    FloorItem *const floorItem = new FloorItem(id,
364
        itemId,
365
        x, y,
366
        itemType,
367
        amount,
368
        refine,
369
        color,
370
        identified,
371
        damaged,
372
        cards);
373
    floorItem->postInit(mMap, subX, subY);
374
375
    if (!checkForPickup(floorItem))
376
        floorItem->disableHightlight();
377
    mActors.insert(floorItem);
378
    mActorsIdMap[floorItem->getId()] = floorItem;
379
    return floorItem;
380
}
381
382
void ActorManager::destroy(ActorSprite *const actor)
383
{
384
    returnNullptrV(actor)
385
386
    if (actor == localPlayer)
387
        return;
388
389
    mDeleteActors.insert(actor);
390
}
391
392
void ActorManager::erase(ActorSprite *const actor)
393
{
394
    returnNullptrV(actor)
395
396
    if (actor == localPlayer)
397
        return;
398
399
    mActors.erase(actor);
400
    const ActorSpritesMapIterator it = mActorsIdMap.find(actor->getId());
401
    if (it != mActorsIdMap.end() && (*it).second == actor)
402
        mActorsIdMap.erase(it);
403
}
404
405
void ActorManager::undelete(const ActorSprite *const actor)
406
{
407
    returnNullptrV(actor)
408
409
    if (actor == localPlayer)
410
        return;
411
412
    FOR_EACH (ActorSpritesConstIterator, it, mDeleteActors)
413
    {
414
        if (*it == actor)
415
        {
416
            mDeleteActors.erase(*it);
417
            return;
418
        }
419
    }
420
}
421
422
Being *ActorManager::findBeing(const BeingId id) const
423
{
424
    const ActorSpritesMapConstIterator it = mActorsIdMap.find(id);
425
    if (it != mActorsIdMap.end())
426
    {
427
        ActorSprite *const actor = (*it).second;
428
        if ((actor != nullptr) &&
429
            actor->getId() == id &&
430
            actor->getType() != ActorType::FloorItem)
431
        {
432
            return static_cast<Being*>(actor);
433
        }
434
    }
435
    return nullptr;
436
}
437
438
ActorSprite *ActorManager::findActor(const BeingId id) const
439
{
440
    const ActorSpritesMapConstIterator it = mActorsIdMap.find(id);
441
    if (it != mActorsIdMap.end())
442
    {
443
        ActorSprite *const actor = (*it).second;
444
        if ((actor != nullptr) &&
445
            actor->getId() == id)
446
        {
447
            return actor;
448
        }
449
    }
450
    return nullptr;
451
}
452
453
Being *ActorManager::findBeing(const int x, const int y,
454
                               const ActorTypeT type) const
455
{
456
    beingActorFinder.x = CAST_U16(x);
457
    beingActorFinder.y = CAST_U16(y);
458
    beingActorFinder.type = type;
459
460
    const ActorSpritesConstIterator it = std::find_if(
461
        mActors.begin(), mActors.end(), beingActorFinder);
462
463
    return (it == mActors.end()) ? nullptr : static_cast<Being*>(*it);
464
}
465
466
Being *ActorManager::findBeingByPixel(const int x, const int y,
467
                                      const AllPlayers allPlayers) const
468
{
469
    if (mMap == nullptr)
470
        return nullptr;
471
472
    const bool targetDead = mTargetDeadPlayers;
473
    const bool modActive = inputManager.isActionActive(
474
        InputAction::STOP_ATTACK);
475
476
    if (mExtMouseTargeting)
477
    {
478
        Being *tempBeing = nullptr;
479
        bool noBeing(false);
480
481
        for_actorsm
482
        {
483
// disabled for performance
484
//            if (reportTrue(*it == nullptr))
485
//                continue;
486
487
            if ((*it)->getType() == ActorType::Portal)
488
                continue;
489
490
            if ((*it)->getType() == ActorType::FloorItem)
491
            {
492
                if (!noBeing)
493
                {
494
                    const FloorItem *const floor
495
                        = static_cast<const FloorItem*>(*it);
496
                    const int px = floor->getPixelX();
497
                    const int py = floor->getPixelY();
498
                    if ((px - mapTileSize     <= x) &&
499
                        (px + mapTileSize     >  x) &&
500
                        (py - mapTileSize * 2 <= y) &&
501
                        (py + mapTileSize / 2 >  y))
502
                    {
503
                        noBeing = true;
504
                    }
505
                }
506
                continue;
507
            }
508
509
            Being *const being = static_cast<Being*>(*it);
510
511
            if (being->getInfo() != nullptr &&
512
                !(being->getInfo()->isTargetSelection() || modActive))
513
            {
514
                continue;
515
            }
516
517
            if ((being->mAction != BeingAction::DEAD ||
518
                (targetDead && being->getType() == ActorType::Player)) &&
519
                (allPlayers == AllPlayers_true || being != localPlayer))
520
            {
521
                const int px = being->getPixelX();
522
                const int py = being->getPixelY();
523
                if ((px - mapTileSize / 2 <= x) &&
524
                    (px + mapTileSize / 2 >  x) &&
525
                    (py - mapTileSize     <= y) &&
526
                    (py                   >  y))
527
                {
528
                    return being;
529
                }
530
                else if (!noBeing &&
531
                         (px - mapTileSize     <= x) &&
532
                         (px + mapTileSize     >  x) &&
533
                         (py - mapTileSize * 2 <= y) &&
534
                         (py + mapTileSize / 2 >  y))
535
                {
536
                    if (tempBeing != nullptr)
537
                        noBeing = true;
538
                    else
539
                        tempBeing = being;
540
                }
541
            }
542
        }
543
544
        if (noBeing)
545
            return nullptr;
546
        return tempBeing;
547
    }
548
    for_actorsm
549
    {
550
// disabled for performance
551
//            if (reportTrue(*it == nullptr))
552
//                continue;
553
554
        if ((*it)->getType() == ActorType::Portal ||
555
            (*it)->getType() == ActorType::FloorItem)
556
        {
557
            continue;
558
        }
559
560
        Being *const being = static_cast<Being*>(*it);
561
562
        if (being->getInfo() != nullptr &&
563
            !(being->getInfo()->isTargetSelection() || modActive))
564
        {
565
            continue;
566
        }
567
568
        const int px = being->getPixelX();
569
        const int py = being->getPixelY();
570
        if ((px - mapTileSize / 2 <= x) &&
571
            (px + mapTileSize / 2 >  x) &&
572
            (py - mapTileSize     <= y) &&
573
            (py                   >  y))
574
        {
575
            return being;
576
        }
577
    }
578
    return nullptr;
579
}
580
581
void ActorManager::findBeingsByPixel(STD_VECTOR<ActorSprite*> &beings,
582
                                     const int x, const int y,
583
                                     const AllPlayers allPlayers) const
584
{
585
    if (mMap == nullptr)
586
        return;
587
588
    const int xtol = mapTileSize / 2;
589
    const int uptol = mapTileSize;
590
    const bool modActive = inputManager.isActionActive(
591
        InputAction::STOP_ATTACK);
592
593
    for_actors
594
    {
595
        ActorSprite *const actor = *it;
596
597
// disabled for performance
598
//        if (reportTrue(actor == nullptr))
599
//            continue;
600
601
        const ActorTypeT actorType = actor->getType();
602
        switch (actorType)
603
        {
604
            default:
605
            case ActorType::Unknown:
606
            case ActorType::Avatar:
607
            case ActorType::Portal:
608
                break;
609
            case ActorType::FloorItem:
610
                if ((actor->getPixelX() - xtol <= x) &&
611
                    (actor->getPixelX() + xtol > x) &&
612
                    (actor->getPixelY() - uptol <= y) &&
613
                    (actor->getPixelY() > y))
614
                {
615
                    beings.push_back(actor);
616
                }
617
                break;
618
            case ActorType::Player:
619
            case ActorType::Npc:
620
            case ActorType::Monster:
621
            case ActorType::Pet:
622
            case ActorType::Mercenary:
623
            case ActorType::Homunculus:
624
            case ActorType::SkillUnit:
625
            case ActorType::Elemental:
626
            {
627
                const Being *const being = static_cast<const Being*>(*it);
628
                if (being == nullptr)
629
                    continue;
630
                if ((being->getInfo() != nullptr) &&
631
                    !(being->getInfo()->isTargetSelection() || modActive))
632
                {
633
                    continue;
634
                }
635
                if ((being->isAlive() ||
636
                    (mTargetDeadPlayers &&
637
                    actorType == ActorType::Player)) &&
638
                    (allPlayers == AllPlayers_true ||
639
                    being != localPlayer))
640
                {
641
                    if ((actor->getPixelX() - xtol <= x) &&
642
                        (actor->getPixelX() + xtol > x) &&
643
                        (actor->getPixelY() - uptol <= y) &&
644
                        (actor->getPixelY() > y))
645
                    {
646
                        beings.push_back(actor);
647
                    }
648
                }
649
                break;
650
            }
651
        }
652
    }
653
}
654
655
Being *ActorManager::findPortalByTile(const int x, const int y) const
656
{
657
    if (mMap == nullptr)
658
        return nullptr;
659
660
    for_actorsm
661
    {
662
// disabled for performance
663
//        if (reportTrue(*it == nullptr))
664
//            continue;
665
666
        if ((*it)->getType() != ActorType::Portal)
667
            continue;
668
669
        Being *const being = static_cast<Being*>(*it);
670
671
        if (being->getTileX() == x && being->getTileY() == y)
672
            return being;
673
    }
674
675
    return nullptr;
676
}
677
678
FloorItem *ActorManager::findItem(const BeingId id) const
679
{
680
    const ActorSpritesMapConstIterator it = mActorsIdMap.find(id);
681
    if (it != mActorsIdMap.end())
682
    {
683
        ActorSprite *const actor = (*it).second;
684
        returnNullptr(nullptr, actor)
685
        if (actor->getId() == id &&
686
            actor->getType() == ActorType::FloorItem)
687
        {
688
            return static_cast<FloorItem*>(actor);
689
        }
690
    }
691
    return nullptr;
692
}
693
694
FloorItem *ActorManager::findItem(const int x, const int y) const
695
{
696
    for_actorsm
697
    {
698
// disabled for performance
699
//        if (reportTrue(*it == nullptr))
700
//            continue;
701
702
        if ((*it)->getTileX() == x && (*it)->getTileY() == y &&
703
            (*it)->getType() == ActorType::FloorItem)
704
        {
705
            return static_cast<FloorItem*>(*it);
706
        }
707
    }
708
709
    return nullptr;
710
}
711
712
bool ActorManager::pickUpAll(const int x1, const int y1,
713
                             const int x2, const int y2,
714
                             const bool serverBuggy) const
715
{
716
    if (localPlayer == nullptr)
717
        return false;
718
719
    bool finded(false);
720
    const bool allowAll = mPickupItemsSet.find(std::string()) !=
721
        mPickupItemsSet.end();
722
    if (!serverBuggy)
723
    {
724
        for_actorsm
725
        {
726
// disabled for performance
727
//            if (reportTrue(*it == nullptr))
728
//                continue;
729
730
            if ((*it)->getType() == ActorType::FloorItem
731
                && ((*it)->getTileX() >= x1 && (*it)->getTileX() <= x2)
732
                && ((*it)->getTileY() >= y1 && (*it)->getTileY() <= y2))
733
            {
734
                FloorItem *const item = static_cast<FloorItem*>(*it);
735
                if (allowAll)
736
                {
737
                    if (mIgnorePickupItemsSet.find(item->getName())
738
                        == mIgnorePickupItemsSet.end())
739
                    {
740
                        if (localPlayer->pickUp(item))
741
                            finded = true;
742
                    }
743
                }
744
                else
745
                {
746
                    if (mPickupItemsSet.find(item->getName())
747
                        != mPickupItemsSet.end())
748
                    {
749
                        if (localPlayer->pickUp(item))
750
                            finded = true;
751
                    }
752
                }
753
            }
754
        }
755
    }
756
    else if (PacketLimiter::checkPackets(PacketType::PACKET_PICKUP))
757
    {
758
        FloorItem *item = nullptr;
759
        unsigned cnt = 65535;
760
        for_actorsm
761
        {
762
// disabled for performance
763
//            if (reportTrue(*it == nullptr))
764
//                continue;
765
766
            if ((*it)->getType() == ActorType::FloorItem
767
                && ((*it)->getTileX() >= x1 && (*it)->getTileX() <= x2)
768
                && ((*it)->getTileY() >= y1 && (*it)->getTileY() <= y2))
769
            {
770
                FloorItem *const tempItem = static_cast<FloorItem*>(*it);
771
                if (tempItem->getPickupCount() < cnt)
772
                {
773
                    if (allowAll)
774
                    {
775
                        if (mIgnorePickupItemsSet.find(tempItem->getName())
776
                            == mIgnorePickupItemsSet.end())
777
                        {
778
                            item = tempItem;
779
                            cnt = item->getPickupCount();
780
                            if (cnt == 0)
781
                            {
782
                                item->incrementPickup();
783
                                localPlayer->pickUp(item);
784
                                return true;
785
                            }
786
                        }
787
                    }
788
                    else
789
                    {
790
                        if (mPickupItemsSet.find(tempItem->getName())
791
                            != mPickupItemsSet.end())
792
                        {
793
                            item = tempItem;
794
                            cnt = item->getPickupCount();
795
                            if (cnt == 0)
796
                            {
797
                                item->incrementPickup();
798
                                localPlayer->pickUp(item);
799
                                return true;
800
                            }
801
                        }
802
                    }
803
                }
804
            }
805
        }
806
        if ((item != nullptr) && localPlayer->pickUp(item))
807
            finded = true;
808
    }
809
    return finded;
810
}
811
812
bool ActorManager::pickUpNearest(const int x, const int y,
813
                                 int maxdist) const
814
{
815
    if (localPlayer == nullptr)
816
        return false;
817
818
    maxdist = maxdist * maxdist;
819
    FloorItem *closestItem = nullptr;
820
    int dist = 0;
821
    const bool allowAll = mPickupItemsSet.find(std::string()) !=
822
        mPickupItemsSet.end();
823
824
    for_actorsm
825
    {
826
// disabled for performance
827
//        if (reportTrue(*it == nullptr))
828
//            continue;
829
830
        if ((*it)->getType() == ActorType::FloorItem)
831
        {
832
            FloorItem *const item = static_cast<FloorItem*>(*it);
833
834
            const int d = (item->getTileX() - x) * (item->getTileX() - x)
835
                + (item->getTileY() - y) * (item->getTileY() - y);
836
837
            if ((d < dist || closestItem == nullptr) &&
838
                (!mTargetOnlyReachable || localPlayer->isReachable(
839
                item->getTileX(), item->getTileY(),
840
                false)))
841
            {
842
                if (allowAll)
843
                {
844
                    if (mIgnorePickupItemsSet.find(item->getName())
845
                        == mIgnorePickupItemsSet.end())
846
                    {
847
                        dist = d;
848
                        closestItem = item;
849
                    }
850
                }
851
                else
852
                {
853
                    if (mPickupItemsSet.find(item->getName())
854
                        != mPickupItemsSet.end())
855
                    {
856
                        dist = d;
857
                        closestItem = item;
858
                    }
859
                }
860
            }
861
        }
862
    }
863
    if ((closestItem != nullptr) && dist <= maxdist)
864
        return localPlayer->pickUp(closestItem);
865
866
    return false;
867
}
868
869
Being *ActorManager::findBeingByName(const std::string &name,
870
                                     const ActorTypeT type) const
871
{
872
    for_actorsm
873
    {
874
// disabled for performance
875
//        if (reportTrue(*it == nullptr))
876
//            continue;
877
878
        if ((*it)->getType() == ActorType::FloorItem
879
            || (*it)->getType() == ActorType::Portal)
880
        {
881
            continue;
882
        }
883
884
        Being *const being = static_cast<Being*>(*it);
885
        if (being->getName() == name &&
886
            (type == ActorType::Unknown || type == being->getType()))
887
        {
888
            return being;
889
        }
890
    }
891
    return nullptr;
892
}
893
894
Being *ActorManager::findNearestByName(const std::string &name,
895
                                       const ActorTypeT &type) const
896
{
897
    if (localPlayer == nullptr)
898
        return nullptr;
899
900
    int dist = 0;
901
    Being* closestBeing = nullptr;
902
    int x = localPlayer->getTileX();
903
    int y = localPlayer->getTileY();
904
905
    for_actorsm
906
    {
907
// disabled for performance
908
//        if (reportTrue(*it == nullptr))
909
//            continue;
910
911
        if ((*it)->getType() == ActorType::FloorItem
912
            || (*it)->getType() == ActorType::Portal)
913
        {
914
            continue;
915
        }
916
917
        Being *const being = static_cast<Being*>(*it);
918
919
        if ((being != nullptr) && being->getName() == name &&
920
            (type == ActorType::Unknown || type == being->getType()))
921
        {
922
            if (being->getType() == ActorType::Player)
923
            {
924
                return being;
925
            }
926
            const int d = (being->getTileX() - x) * (being->getTileX() - x)
927
                + (being->getTileY() - y) * (being->getTileY() - y);
928
929
            if (validateBeing(nullptr, being, type, nullptr, 50)
930
                && (d < dist || closestBeing == nullptr))
931
            {
932
                dist = d;
933
                closestBeing = being;
934
            }
935
        }
936
    }
937
    return closestBeing;
938
}
939
940
const ActorSprites &ActorManager::getAll() const
941
{
942
    return mActors;
943
}
944
945
void ActorManager::logic()
946
{
947
    BLOCK_START("ActorManager::logic")
948
    for_actors
949
    {
950
// disabled for performance
951
//        if (reportFalse(*it))
952
        (*it)->logic();
953
    }
954
955
    if (mDeleteActors.empty())
956
    {
957
        BLOCK_END("ActorManager::logic")
958
        return;
959
    }
960
961
    BLOCK_START("ActorManager::logic 1")
962
    FOR_EACH (ActorSpritesConstIterator, it, mDeleteActors)
963
    {
964
        const ActorSprite *const actor = *it;
965
        const ActorTypeT &type = actor->getType();
966
        if (type == ActorType::Player)
967
        {
968
            const Being *const being = static_cast<const Being*>(actor);
969
            being->addToCache();
970
            if (beingEquipmentWindow != nullptr)
971
                beingEquipmentWindow->resetBeing(being);
972
        }
973
        if (localPlayer != nullptr)
974
        {
975
            if (localPlayer->getTarget() == actor)
976
                localPlayer->setTarget(nullptr);
977
            if (localPlayer->getPickUpTarget() == actor)
978
                localPlayer->unSetPickUpTarget();
979
        }
980
        if (viewport != nullptr)
981
            viewport->clearHover(*it);
982
    }
983
984
    FOR_EACH (ActorSpritesConstIterator, it, mDeleteActors)
985
    {
986
        ActorSprite *actor = *it;
987
        mActors.erase(actor);
988
989
        if (actor != nullptr)
990
        {
991
            const ActorSpritesMapIterator itr = mActorsIdMap.find(
992
                actor->getId());
993
            if (itr != mActorsIdMap.end() && (*itr).second == actor)
994
                mActorsIdMap.erase(itr);
995
996
            delete actor;
997
        }
998
    }
999
1000
    mDeleteActors.clear();
1001
    BLOCK_END("ActorManager::logic 1")
1002
    BLOCK_END("ActorManager::logic")
1003
}
1004
1005
5
void ActorManager::clear()
1006
{
1007
5
    if (beingEquipmentWindow != nullptr)
1008
        beingEquipmentWindow->setBeing(nullptr);
1009
1010
5
    if (localPlayer != nullptr)
1011
    {
1012
5
        localPlayer->setTarget(nullptr);
1013
5
        localPlayer->unSetPickUpTarget();
1014
10
        mActors.erase(localPlayer);
1015
    }
1016
1017
15
    for_actors
1018
7
        delete *it;
1019
10
    mActors.clear();
1020
10
    mDeleteActors.clear();
1021
10
    mActorsIdMap.clear();
1022
1023
5
    if (localPlayer != nullptr)
1024
    {
1025
10
        mActors.insert(localPlayer);
1026
10
        mActorsIdMap[localPlayer->getId()] = localPlayer;
1027
    }
1028
1029
10
    mChars.clear();
1030
5
}
1031
1032
Being *ActorManager::findNearestPvpPlayer() const
1033
{
1034
    if (localPlayer == nullptr)
1035
        return nullptr;
1036
1037
    // don't attack players
1038
    if (settings.pvpAttackType == 3)
1039
        return nullptr;
1040
1041
    const Game *const game = Game::instance();
1042
    if (game == nullptr)
1043
        return nullptr;
1044
1045
    const Map *const map = game->getCurrentMap();
1046
    if (map == nullptr)
1047
        return nullptr;
1048
1049
    const int mapPvpMode = map->getPvpMode();
1050
    Being *target = nullptr;
1051
    int minDistSquared = 20000;
1052
1053
    for_actors
1054
    {
1055
        if ((*it)->getType() != ActorType::Player)
1056
            continue;
1057
1058
        Being *const being = static_cast<Being*>(*it);
1059
1060
        if (reportTrue(being == nullptr) ||
1061
            !being->isAlive() ||
1062
            localPlayer == being)
1063
        {
1064
            continue;
1065
        }
1066
1067
        const int teamId = being->getTeamId();
1068
        // this condition is very TMW-specific
1069
        if (!((mapPvpMode != 0) || (teamId != 0)))
1070
            continue;
1071
1072
        if (!LocalPlayer::checAttackPermissions(being))
1073
            continue;
1074
1075
        const int dx = being->getTileX() - localPlayer->getTileX();
1076
        const int dy = being->getTileY() - localPlayer->getTileY();
1077
        const int distSquared = dx * dx + dy * dy;
1078
        if (distSquared < minDistSquared)
1079
        {
1080
            minDistSquared = distSquared;
1081
            target = being;
1082
        }
1083
    }
1084
1085
    return target;
1086
}
1087
1088
1089
Being *ActorManager::findNearestLivingBeing(const int x, const int y,
1090
                                            const int maxTileDist,
1091
                                            const ActorTypeT type,
1092
                                            const Being *const excluded) const
1093
{
1094
    const int maxDist = maxTileDist * mapTileSize;
1095
1096
    return findNearestLivingBeing(nullptr, maxDist,
1097
        type,
1098
        x, y,
1099
        excluded,
1100
        AllowSort_true);
1101
}
1102
1103
2
Being *ActorManager::findNearestLivingBeing(const Being *const aroundBeing,
1104
                                            const int maxDist,
1105
                                            const ActorTypeT type,
1106
                                            const AllowSort allowSort) const
1107
{
1108
2
    if (aroundBeing == nullptr)
1109
        return nullptr;
1110
1111
4
    return findNearestLivingBeing(aroundBeing,
1112
        maxDist,
1113
        type,
1114
2
        aroundBeing->getTileX(),
1115
2
        aroundBeing->getTileY(),
1116
        aroundBeing,
1117
2
        allowSort);
1118
}
1119
1120
2
Being *ActorManager::findNearestLivingBeing(const Being *const aroundBeing,
1121
                                            int maxDist,
1122
                                            const ActorTypeT &type,
1123
                                            const int x, const int y,
1124
                                            const Being *const excluded,
1125
                                            const AllowSort allowSort) const
1126
{
1127

2
    if ((aroundBeing == nullptr) || (localPlayer == nullptr))
1128
        return nullptr;
1129
1130
2
    std::set<std::string> attackMobs;
1131
4
    std::set<std::string> priorityMobs;
1132
4
    std::set<std::string> ignoreAttackMobs;
1133
4
    StringIntMap attackMobsMap;
1134
4
    StringIntMap priorityMobsMap;
1135
2
    int defaultAttackIndex = 10000;
1136
2
    int defaultPriorityIndex = 10000;
1137
2
    const int attackRange = localPlayer->getAttackRange();
1138
1139
2
    bool specialDistance = false;
1140
4
    if (settings.moveToTargetType == 11
1141

2
        && localPlayer->getAttackRange() > 2)
1142
    {
1143
        specialDistance = true;
1144
    }
1145
1146
2
    maxDist = maxDist * maxDist;
1147
1148
    const bool cycleSelect = allowSort == AllowSort_true
1149

2
        && ((mCyclePlayers && type == ActorType::Player)
1150

1
        || (mCycleMonsters && type == ActorType::Monster)
1151
        || (mCycleNPC && type == ActorType::Npc));
1152
1153
    const bool filtered = allowSort == AllowSort_true
1154


8
        && config.getBoolValue("enableAttackFilter")
1155

4
        && type == ActorType::Monster;
1156
    const bool modActive = inputManager.isActionActive(
1157
2
        InputAction::STOP_ATTACK);
1158
1159
2
    bool ignoreDefault = false;
1160
2
    if (filtered)
1161
    {
1162
2
        attackMobs = mAttackMobsSet;
1163
2
        priorityMobs = mPriorityAttackMobsSet;
1164
2
        ignoreAttackMobs = mIgnoreAttackMobsSet;
1165
2
        attackMobsMap = mAttackMobsMap;
1166
2
        priorityMobsMap = mPriorityAttackMobsMap;
1167
1
        beingActorSorter.attackBeings = &attackMobsMap;
1168
1
        beingActorSorter.priorityBeings = &priorityMobsMap;
1169
1
        beingActorSorter.specialDistance = specialDistance;
1170
1
        beingActorSorter.attackRange = attackRange;
1171
4
        if (ignoreAttackMobs.find(std::string()) != ignoreAttackMobs.end())
1172
            ignoreDefault = true;
1173
4
        StringIntMapCIter itr = attackMobsMap.find(std::string());
1174
1
        if (itr != attackMobsMap.end())
1175
1
            defaultAttackIndex = (*itr).second;
1176
3
        itr = priorityMobsMap.find(std::string());
1177
1
        if (itr != priorityMobsMap.end())
1178
            defaultPriorityIndex = (*itr).second;
1179
    }
1180
1181
2
    if (cycleSelect)
1182
    {
1183
4
        STD_VECTOR<Being*> sortedBeings;
1184
1185
6
        FOR_EACH (ActorSprites::iterator, i, mActors)
1186
        {
1187
//  disabled for performance
1188
//            if (reportTrue(*i == nullptr))
1189
//                continue;
1190
1191
            if ((*i)->getType() == ActorType::FloorItem
1192
                || (*i)->getType() == ActorType::Portal)
1193
            {
1194
                continue;
1195
            }
1196
1197
            Being *const being = static_cast<Being*>(*i);
1198
1199
            if (filtered)
1200
            {
1201
                if (ignoreAttackMobs.find(being->getName())
1202
                    != ignoreAttackMobs.end())
1203
                {
1204
                    continue;
1205
                }
1206
                if (ignoreDefault && attackMobs.find(being->getName())
1207
                    == attackMobs.end() && priorityMobs.find(being->getName())
1208
                    == priorityMobs.end())
1209
                {
1210
                    continue;
1211
                }
1212
            }
1213
1214
            if ((being->getInfo() != nullptr)
1215
                && !(being->getInfo()->isTargetSelection() || modActive))
1216
            {
1217
                continue;
1218
            }
1219
1220
            if (validateBeing(aroundBeing, being, type, nullptr, maxDist))
1221
            {
1222
                if (being != excluded)
1223
                    sortedBeings.push_back(being);
1224
            }
1225
        }
1226
1227
        // no selectable beings
1228
2
        if (sortedBeings.empty())
1229
            return nullptr;
1230
1231
        beingActorSorter.x = x;
1232
        beingActorSorter.y = y;
1233
        if (filtered)
1234
        {
1235
            beingActorSorter.attackBeings = &attackMobsMap;
1236
            beingActorSorter.defaultAttackIndex = defaultAttackIndex;
1237
            beingActorSorter.priorityBeings = &priorityMobsMap;
1238
            beingActorSorter.defaultPriorityIndex = defaultPriorityIndex;
1239
        }
1240
        else
1241
        {
1242
            beingActorSorter.attackBeings = nullptr;
1243
            beingActorSorter.priorityBeings = nullptr;
1244
        }
1245
        std::sort(sortedBeings.begin(), sortedBeings.end(), beingActorSorter);
1246
        if (filtered)
1247
        {
1248
            beingActorSorter.attackBeings = nullptr;
1249
            beingActorSorter.priorityBeings = nullptr;
1250
        }
1251
1252
        if (localPlayer->getTarget() == nullptr)
1253
        {
1254
            Being *const target = sortedBeings.at(0);
1255
1256
            if (specialDistance && target->getType() == ActorType::Monster
1257
                && target->getDistance() <= 2)
1258
            {
1259
                return nullptr;
1260
            }
1261
            // if no selected being in vector, return first nearest being
1262
            return target;
1263
        }
1264
1265
        beingEqualActorFinder.findBeing = localPlayer->getTarget();
1266
        STD_VECTOR<Being*>::const_iterator i = std::find_if(
1267
            sortedBeings.begin(), sortedBeings.end(), beingEqualActorFinder);
1268
1269
        if (i == sortedBeings.end() || ++i == sortedBeings.end())
1270
        {
1271
            // if no selected being in vector, return first nearest being
1272
            return sortedBeings.at(0);
1273
        }
1274
1275
        // we find next being after target
1276
        return *i;
1277
    }
1278
1279
    int dist = 0;
1280
    int index = defaultPriorityIndex;
1281
    Being *closestBeing = nullptr;
1282
1283
    FOR_EACH (ActorSprites::iterator, i, mActors)
1284
    {
1285
//  disabled for performance
1286
//            if (reportTrue(*i == nullptr))
1287
//                continue;
1288
1289
        if ((*i)->getType() == ActorType::FloorItem ||
1290
            (*i)->getType() == ActorType::Portal)
1291
        {
1292
            continue;
1293
        }
1294
        Being *const being = static_cast<Being*>(*i);
1295
1296
        if (filtered)
1297
        {
1298
            if (ignoreAttackMobs.find(being->getName())
1299
                != ignoreAttackMobs.end())
1300
            {
1301
                continue;
1302
            }
1303
            if (ignoreDefault && attackMobs.find(being->getName())
1304
                == attackMobs.end() && priorityMobs.find(being->getName())
1305
                == priorityMobs.end())
1306
            {
1307
                continue;
1308
            }
1309
        }
1310
1311
        if ((being->getInfo() != nullptr)
1312
            && !(being->getInfo()->isTargetSelection() || modActive))
1313
        {
1314
            continue;
1315
        }
1316
1317
        const bool valid = validateBeing(aroundBeing, being,
1318
                                             type, excluded, 50);
1319
        int d = being->getDistance();
1320
        if (being->getType() != ActorType::Monster
1321
            || !mTargetOnlyReachable)
1322
        {   // if distance not calculated, use old distance
1323
            d = (being->getTileX() - x) * (being->getTileX() - x)
1324
                + (being->getTileY() - y) * (being->getTileY() - y);
1325
        }
1326
1327
        if (!valid)
1328
            continue;
1329
1330
        if (specialDistance && being->getDistance() <= 2
1331
            && being->getType() == type)
1332
        {
1333
            continue;
1334
        }
1335
1336
//            logger->log("being name:" + being->getName());
1337
//            logger->log("index:" + toString(index));
1338
//            logger->log("d:" + toString(d));
1339
1340
        if (!filtered && (d <= dist || (closestBeing == nullptr)))
1341
        {
1342
            dist = d;
1343
            closestBeing = being;
1344
        }
1345
        else if (filtered)
1346
        {
1347
            int w2 = defaultPriorityIndex;
1348
            if (closestBeing != nullptr)
1349
            {
1350
                const StringIntMapCIter it2 =  priorityMobsMap.find(
1351
                    being->getName());
1352
                if (it2 != priorityMobsMap.end())
1353
                    w2 = (*it2).second;
1354
1355
                if (w2 < index)
1356
                {
1357
                    dist = d;
1358
                    closestBeing = being;
1359
                    index = w2;
1360
                    continue;
1361
                }
1362
                if (w2 == index && d <= dist)
1363
                {
1364
                    dist = d;
1365
                    closestBeing = being;
1366
                    index = w2;
1367
                    continue;
1368
                }
1369
            }
1370
1371
            if (closestBeing == nullptr)
1372
            {
1373
                dist = d;
1374
                closestBeing = being;
1375
                const StringIntMapCIter it1 = priorityMobsMap.find(
1376
                    being->getName());
1377
                if (it1 != priorityMobsMap.end())
1378
                    index = (*it1).second;
1379
                else
1380
                    index = defaultPriorityIndex;
1381
            }
1382
        }
1383
    }
1384
    return (maxDist >= dist) ? closestBeing : nullptr;
1385
}
1386
1387
bool ActorManager::validateBeing(const Being *const aroundBeing,
1388
                                 Being *const being,
1389
                                 const ActorTypeT &type,
1390
                                 const Being* const excluded,
1391
                                 const int maxCost) const
1392
{
1393
    if (localPlayer == nullptr)
1394
        return false;
1395
    return (being != nullptr) && ((being->getType() == type
1396
        || type == ActorType::Unknown) && (being->isAlive()
1397
        || (mTargetDeadPlayers && type == ActorType::Player))
1398
        && being != aroundBeing) && being != excluded
1399
        && (type != ActorType::Monster || !mTargetOnlyReachable
1400
        || localPlayer->isReachable(being, maxCost));
1401
}
1402
1403
#ifdef TMWA_SUPPORT
1404
void ActorManager::healTarget() const
1405
{
1406
    if (localPlayer == nullptr)
1407
        return;
1408
1409
    heal(localPlayer->getTarget());
1410
}
1411
1412
void ActorManager::heal(const Being *const target) const
1413
{
1414
    if (Net::getNetworkType() != ServerType::TMWATHENA)
1415
        return;
1416
1417
    if (localPlayer == nullptr ||
1418
        chatWindow == nullptr ||
1419
        !localPlayer->isAlive() ||
1420
        !playerHandler->canUseMagic())
1421
    {
1422
        return;
1423
    }
1424
1425
    // self
1426
    if (target != nullptr &&
1427
        localPlayer->getName() == target->getName())
1428
    {
1429
        if (PlayerInfo::getAttribute(Attributes::PLAYER_MP) >= 6
1430
            && PlayerInfo::getAttribute(Attributes::PLAYER_HP)
1431
            != PlayerInfo::getAttribute(Attributes::PLAYER_MAX_HP))
1432
        {
1433
            if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1434
                return;
1435
            chatWindow->localChatInput(mSpellHeal1);
1436
        }
1437
    }
1438
    // magic levels < 2
1439
    else if (PlayerInfo::getSkillLevel(340) < 2 ||
1440
             PlayerInfo::getSkillLevel(341) < 2)
1441
    {
1442
        if (PlayerInfo::getAttribute(Attributes::PLAYER_MP) >= 6)
1443
        {
1444
            if (target != nullptr &&
1445
                target->getType() != ActorType::Monster)
1446
            {
1447
                if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1448
                    return;
1449
                chatWindow->localChatInput(mSpellHeal1 + " "
1450
                                           + target->getName());
1451
            }
1452
            else if (PlayerInfo::getAttribute(Attributes::PLAYER_HP)
1453
                     != PlayerInfo::getAttribute(Attributes::PLAYER_MAX_HP))
1454
            {
1455
                if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1456
                    return;
1457
                chatWindow->localChatInput(mSpellHeal1);
1458
            }
1459
        }
1460
    }
1461
    // magic level >= 2 and not self
1462
    else
1463
    {
1464
        // mp > 10 and target not monster
1465
        if (PlayerInfo::getAttribute(Attributes::PLAYER_MP) >= 10 &&
1466
            target != nullptr &&
1467
            target->getType() != ActorType::Monster)
1468
        {
1469
            // target not enemy
1470
            if (playerRelations.getRelation(target->getName()) !=
1471
                Relation::ENEMY2)
1472
            {
1473
                if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1474
                    return;
1475
                chatWindow->localChatInput(mSpellHeal2 + " "
1476
                    + target->getName());
1477
            }
1478
            // target enemy
1479
            else
1480
            {
1481
                if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1482
                    return;
1483
                chatWindow->localChatInput(mSpellHeal1);
1484
            }
1485
        }
1486
        // heal self if selected monster or selection empty
1487
        else if ((target == nullptr || target->getType() == ActorType::Monster)
1488
                 && PlayerInfo::getAttribute(Attributes::PLAYER_MP) >= 6
1489
                 && PlayerInfo::getAttribute(Attributes::PLAYER_HP)
1490
                 != PlayerInfo::getAttribute(Attributes::PLAYER_MAX_HP))
1491
        {
1492
            if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1493
                return;
1494
            chatWindow->localChatInput(mSpellHeal1);
1495
        }
1496
    }
1497
}
1498
#endif  // TMWA_SUPPORT
1499
1500
Being* ActorManager::findMostDamagedPlayer(const int maxTileDist) const
1501
{
1502
    if (localPlayer == nullptr)
1503
        return nullptr;
1504
1505
    int maxDamageTaken = 0;
1506
    Being *target = nullptr;
1507
1508
    for_actors
1509
    {
1510
        if ((*it)->getType() != ActorType::Player)
1511
            continue;
1512
1513
        Being *const being = static_cast<Being*>(*it);
1514
1515
        if ((being == nullptr) || !being->isAlive() ||  // don't heal dead
1516
            playerRelations.getRelation(being->getName()) ==
1517
            Relation::ENEMY2 ||                         // don't heal enemy
1518
            localPlayer == being)                       // don't heal self
1519
        {
1520
            continue;
1521
        }
1522
1523
        const int dx = being->getTileX() - localPlayer->getTileX();
1524
        const int dy = being->getTileY() - localPlayer->getTileY();
1525
        const int distance = fastSqrtInt(dx * dx + dy * dy);
1526
1527
        if (distance > maxTileDist)
1528
            continue;
1529
1530
        if (being->getDamageTaken() > maxDamageTaken)
1531
        {
1532
            maxDamageTaken = being->getDamageTaken();
1533
            target = being;
1534
        }
1535
    }
1536
1537
    return target;
1538
}
1539
1540
#ifdef TMWA_SUPPORT
1541
void ActorManager::itenplz() const
1542
{
1543
    if (Net::getNetworkType() != ServerType::TMWATHENA)
1544
        return;
1545
    if (localPlayer == nullptr ||
1546
        chatWindow == nullptr ||
1547
        !localPlayer->isAlive() ||
1548
        !playerHandler->canUseMagic())
1549
    {
1550
        return;
1551
    }
1552
1553
    if (!PacketLimiter::limitPackets(PacketType::PACKET_CHAT))
1554
        return;
1555
1556
    chatWindow->localChatInput(mSpellItenplz);
1557
}
1558
#endif  // TMWA_SUPPORT
1559
1560
bool ActorManager::hasActorSprite(const ActorSprite *const actor) const
1561
{
1562
    for_actors
1563
    {
1564
        if (actor == *it)
1565
            return true;
1566
    }
1567
1568
    return false;
1569
}
1570
1571
void ActorManager::addBlock(const BeingId id)
1572
{
1573
    mBlockedBeings.insert(id);
1574
}
1575
1576
void ActorManager::deleteBlock(const BeingId id)
1577
{
1578
    mBlockedBeings.erase(id);
1579
}
1580
1581
bool ActorManager::isBlocked(const BeingId id) const
1582
{
1583
    return mBlockedBeings.find(id) != mBlockedBeings.end();
1584
}
1585
1586
void ActorManager::printAllToChat()
1587
{
1588
    // TRANSLATORS: visible beings on map
1589
    printBeingsToChat(_("Visible on map"));
1590
}
1591
1592
void ActorManager::printBeingsToChat(const std::string &header) const
1593
{
1594
    if (debugChatTab == nullptr)
1595
        return;
1596
1597
    debugChatTab->chatLog("---------------------------------------",
1598
        ChatMsgType::BY_SERVER,
1599
        IgnoreRecord_false,
1600
        TryRemoveColors_true);
1601
    debugChatTab->chatLog(header,
1602
        ChatMsgType::BY_SERVER,
1603
        IgnoreRecord_false,
1604
        TryRemoveColors_true);
1605
    for_actors
1606
    {
1607
// disabled for performance
1608
//        if (reportTrue(*it == nullptr))
1609
//            continue;
1610
1611
        if ((*it)->getType() == ActorType::FloorItem)
1612
            continue;
1613
1614
        const Being *const being = static_cast<const Being*>(*it);
1615
1616
        debugChatTab->chatLog(strprintf("%s (%d,%d) %d",
1617
            being->getName().c_str(), being->getTileX(), being->getTileY(),
1618
            toInt(being->getSubType(), int)),
1619
            ChatMsgType::BY_SERVER,
1620
            IgnoreRecord_false,
1621
            TryRemoveColors_true);
1622
        if (mActorsIdMap.find(being->getId()) == mActorsIdMap.end())
1623
        {
1624
            debugChatTab->chatLog("missing in id map: %s",
1625
                being->getName().c_str());
1626
        }
1627
    }
1628
    debugChatTab->chatLog("---------------------------------------",
1629
        ChatMsgType::BY_SERVER,
1630
        IgnoreRecord_false,
1631
        TryRemoveColors_true);
1632
    FOR_EACH (ActorSpritesMapConstIterator, itr, mActorsIdMap)
1633
    {
1634
        const ActorSprite *const actor = (*itr).second;
1635
        if (actor == nullptr)
1636
            continue;
1637
        if (actor->getId() != (*itr).first)
1638
            debugChatTab->chatLog("Actor with wrong key in map", "");
1639
1640
        bool found(false);
1641
1642
        for_actors
1643
        {
1644
// disabled for performance
1645
//            if (!*it)
1646
//                continue;
1647
1648
            if ((*it)->getId() == actor->getId())
1649
            {
1650
                found = true;
1651
                break;
1652
            }
1653
        }
1654
        if (!found)
1655
            debugChatTab->chatLog("Actor present in map but not in set", "");
1656
    }
1657
}
1658
1659
void ActorManager::printBeingsToChat(const STD_VECTOR<Being*> &beings,
1660
                                     const std::string &header)
1661
{
1662
    if (debugChatTab == nullptr)
1663
        return;
1664
1665
    debugChatTab->chatLog("---------------------------------------",
1666
        ChatMsgType::BY_SERVER,
1667
        IgnoreRecord_false,
1668
        TryRemoveColors_true);
1669
    debugChatTab->chatLog(header,
1670
        ChatMsgType::BY_SERVER,
1671
        IgnoreRecord_false,
1672
        TryRemoveColors_true);
1673
1674
    FOR_EACH (STD_VECTOR<Being*>::const_iterator, i, beings)
1675
    {
1676
        if (*i == nullptr)
1677
            continue;
1678
1679
        const Being *const being = *i;
1680
1681
        debugChatTab->chatLog(strprintf("%s (%d,%d) %d",
1682
            being->getName().c_str(), being->getTileX(), being->getTileY(),
1683
            toInt(being->getSubType(), int)),
1684
            ChatMsgType::BY_SERVER,
1685
            IgnoreRecord_false,
1686
            TryRemoveColors_true);
1687
    }
1688
    debugChatTab->chatLog("---------------------------------------",
1689
        ChatMsgType::BY_SERVER,
1690
        IgnoreRecord_false,
1691
        TryRemoveColors_true);
1692
}
1693
1694
4
void ActorManager::getPlayerNames(StringVect &names,
1695
                                  const NpcNames npcNames) const
1696
{
1697
4
    names.clear();
1698
1699
12
    for_actors
1700
    {
1701
// disabled for performance
1702
//      if (reportTrue(*it == nullptr))
1703
//          continue;
1704
1705

12
        if ((*it)->getType() == ActorType::FloorItem ||
1706
6
            (*it)->getType() == ActorType::Portal)
1707
        {
1708
            continue;
1709
        }
1710
1711
6
        const Being *const being = static_cast<const Being*>(*it);
1712

12
        if ((being->getType() == ActorType::Player ||
1713
            (being->getType() == ActorType::Npc &&
1714

12
            npcNames == NpcNames_true)) &&
1715
6
            !being->getName().empty())
1716
        {
1717
3
            names.push_back(being->getName());
1718
        }
1719
    }
1720
4
}
1721
1722
void ActorManager::getMobNames(StringVect &names) const
1723
{
1724
    names.clear();
1725
1726
    for_actors
1727
    {
1728
// disabled for performance
1729
//      if (reportTrue(*it == nullptr))
1730
//          continue;
1731
1732
        if ((*it)->getType() == ActorType::FloorItem
1733
            || (*it)->getType() == ActorType::Portal)
1734
        {
1735
            continue;
1736
        }
1737
1738
        const Being *const being = static_cast<const Being*>(*it);
1739
        if (being->getType() == ActorType::Monster &&
1740
            !being->getName().empty())
1741
        {
1742
            names.push_back(being->getName());
1743
        }
1744
    }
1745
}
1746
1747
void ActorManager::updatePlayerNames() const
1748
{
1749
    for_actorsm
1750
    {
1751
// disabled for performance
1752
//      if (reportTrue(*it == nullptr))
1753
//          continue;
1754
1755
        if ((*it)->getType() == ActorType::FloorItem
1756
            || (*it)->getType() == ActorType::Portal)
1757
        {
1758
            continue;
1759
        }
1760
1761
        Being *const being = static_cast<Being*>(*it);
1762
        being->setGoodStatus(-1);
1763
        if (being->getType() == ActorType::Player && !being->getName().empty())
1764
            being->updateName();
1765
    }
1766
}
1767
1768
void ActorManager::updatePlayerColors() const
1769
{
1770
    for_actorsm
1771
    {
1772
// disabled for performance
1773
//      if (reportTrue(*it == nullptr))
1774
//          continue;
1775
1776
        if ((*it)->getType() == ActorType::FloorItem
1777
            || (*it)->getType() == ActorType::Portal)
1778
        {
1779
            continue;
1780
        }
1781
1782
        Being *const being = static_cast<Being*>(*it);
1783
        if (being->getType() == ActorType::Player && !being->getName().empty())
1784
            being->updateColors();
1785
    }
1786
}
1787
1788
void ActorManager::updatePlayerGuild() const
1789
{
1790
    for_actorsm
1791
    {
1792
// disabled for performance
1793
//      if (reportTrue(*it == nullptr))
1794
//          continue;
1795
1796
        if ((*it)->getType() == ActorType::FloorItem
1797
            || (*it)->getType() == ActorType::Portal)
1798
        {
1799
            continue;
1800
        }
1801
1802
        Being *const being = static_cast<Being*>(*it);
1803
        if (being->getType() == ActorType::Player && !being->getName().empty())
1804
            being->updateGuild();
1805
    }
1806
}
1807
1808
#ifdef TMWA_SUPPORT
1809
void ActorManager::parseLevels(std::string levels) const
1810
{
1811
    levels.append(", ");
1812
    size_t f = 0;
1813
    const std::string brkEnd("), ");
1814
    size_t pos = levels.find(brkEnd, f);
1815
1816
    while (pos != std::string::npos)
1817
    {
1818
        std::string part = levels.substr(f, pos - f);
1819
        if (part.empty())
1820
            break;
1821
        const size_t bktPos = part.rfind('(');
1822
        if (bktPos != std::string::npos)
1823
        {
1824
            Being *const being = findBeingByName(part.substr(0, bktPos),
1825
                ActorType::Player);
1826
            if (being != nullptr)
1827
            {
1828
                being->setLevel(atoi(part.substr(bktPos + 1).c_str()));
1829
                being->addToCache();
1830
            }
1831
        }
1832
        f = CAST_SIZE(pos + brkEnd.length());
1833
        pos = levels.find(brkEnd, f);
1834
    }
1835
    updatePlayerNames();
1836
}
1837
#endif  // TMWA_SUPPORT
1838
1839
void ActorManager::optionChanged(const std::string &name)
1840
{
1841
    if (name == "targetDeadPlayers")
1842
        mTargetDeadPlayers = config.getBoolValue("targetDeadPlayers");
1843
    else if (name == "targetOnlyReachable")
1844
        mTargetOnlyReachable = config.getBoolValue("targetOnlyReachable");
1845
    else if (name == "cyclePlayers")
1846
        mCyclePlayers = config.getBoolValue("cyclePlayers");
1847
    else if (name == "cycleMonsters")
1848
        mCycleMonsters = config.getBoolValue("cycleMonsters");
1849
    else if (name == "cycleNPC")
1850
        mCycleNPC = config.getBoolValue("cycleNPC");
1851
    else if (name == "extMouseTargeting")
1852
        mExtMouseTargeting = config.getBoolValue("extMouseTargeting");
1853
    else if (name == "showBadges" || name == "visiblenamespos")
1854
        updateBadges();
1855
    else if (name == "enableIdCollecting")
1856
        mEnableIdCollecting = config.getBoolValue("enableIdCollecting");
1857
}
1858
1859
void ActorManager::removeAttackMob(const std::string &name)
1860
{
1861
    mPriorityAttackMobs.remove(name);
1862
    mAttackMobs.remove(name);
1863
    mIgnoreAttackMobs.remove(name);
1864
    mPriorityAttackMobsSet.erase(name);
1865
    mAttackMobsSet.erase(name);
1866
    mIgnoreAttackMobsSet.erase(name);
1867
    rebuildAttackMobs();
1868
    rebuildPriorityAttackMobs();
1869
    storeAttackList();
1870
}
1871
1872
void ActorManager::removePickupItem(const std::string &name)
1873
{
1874
    mPickupItems.remove(name);
1875
    mPickupItemsSet.erase(name);
1876
    mIgnorePickupItems.remove(name);
1877
    mIgnorePickupItemsSet.erase(name);
1878
    rebuildPickupItems();
1879
    storeAttackList();
1880
}
1881
1882
#define addMobToList(name, mob) \
1883
{\
1884
    const int sz = get##mob##sSize();\
1885
    if (sz > 0)\
1886
    {\
1887
        const int idx = get##mob##Index("");\
1888
        if (idx + 1 == sz)\
1889
        {\
1890
            std::list<std::string>::iterator itr = m##mob##s.end();\
1891
            -- itr;\
1892
            m##mob##s.insert(itr, name);\
1893
        }\
1894
        else\
1895
        {\
1896
            m##mob##s.push_back(name);\
1897
        }\
1898
    }\
1899
    else\
1900
    {\
1901
        m##mob##s.push_back(name);\
1902
    }\
1903
    m##mob##sSet.insert(name);\
1904
    rebuild##mob##s();\
1905
}
1906
1907
#define rebuildMobsList(mob) \
1908
{\
1909
    m##mob##sMap.clear();\
1910
    std::list<std::string>::const_iterator i = m##mob##s.begin();\
1911
    int cnt = 0;\
1912
    while (i != m##mob##s.end())\
1913
    {\
1914
        m##mob##sMap[*i] = cnt;\
1915
        ++ i;\
1916
        ++ cnt;\
1917
    }\
1918
}
1919
1920
void ActorManager::addAttackMob(const std::string &name)
1921
{
1922
    addMobToList(name, AttackMob)
1923
    rebuildPriorityAttackMobs();
1924
    storeAttackList();
1925
}
1926
1927
void ActorManager::addPriorityAttackMob(const std::string &name)
1928
{
1929
    addMobToList(name, PriorityAttackMob)
1930
    storeAttackList();
1931
}
1932
1933
void ActorManager::addIgnoreAttackMob(const std::string &name)
1934
{
1935
    mIgnoreAttackMobs.push_back(name);
1936
    mIgnoreAttackMobsSet.insert(name);
1937
    rebuildAttackMobs();
1938
    rebuildPriorityAttackMobs();
1939
    storeAttackList();
1940
}
1941
1942
void ActorManager::addPickupItem(const std::string &name)
1943
{
1944
    addMobToList(name, PickupItem)
1945
    rebuildPickupItems();
1946
    storeAttackList();
1947
}
1948
1949
void ActorManager::addIgnorePickupItem(const std::string &name)
1950
{
1951
    mIgnorePickupItems.push_back(name);
1952
    mIgnorePickupItemsSet.insert(name);
1953
    rebuildPickupItems();
1954
    storeAttackList();
1955
}
1956
1957
5
void ActorManager::rebuildPriorityAttackMobs()
1958
{
1959
25
    rebuildMobsList(PriorityAttackMob)
1960
5
}
1961
1962
5
void ActorManager::rebuildAttackMobs()
1963
{
1964
40
    rebuildMobsList(AttackMob)
1965
5
}
1966
1967
5
void ActorManager::rebuildPickupItems()
1968
{
1969
40
    rebuildMobsList(PickupItem)
1970
5
}
1971
1972
int ActorManager::getIndexByName(const std::string &name,
1973
                                 const StringIntMap &map)
1974
{
1975
    const StringIntMapCIter i = map.find(name);
1976
    if (i == map.end())
1977
        return -1;
1978
1979
    return (*i).second;
1980
}
1981
1982
int ActorManager::getPriorityAttackMobIndex(const std::string &name) const
1983
{
1984
    return getIndexByName(name, mPriorityAttackMobsMap);
1985
}
1986
1987
int ActorManager::getAttackMobIndex(const std::string &name) const
1988
{
1989
    return getIndexByName(name, mAttackMobsMap);
1990
}
1991
1992
int ActorManager::getPickupItemIndex(const std::string &name) const
1993
{
1994
    return getIndexByName(name, mPickupItemsMap);
1995
}
1996
1997
#define loadList(key, mob) \
1998
{\
1999
    list = unpackList(serverConfig.getValue(key, ""));\
2000
    i = list.begin();\
2001
    i_end = list.end();\
2002
    while (i != i_end)\
2003
    {\
2004
        if ((*i).empty())\
2005
            empty = true;\
2006
        m##mob##s.push_back(*i);\
2007
        m##mob##sSet.insert(*i);\
2008
        ++ i;\
2009
    }\
2010
}
2011
2012
5
void ActorManager::loadAttackList()
2013
{
2014
5
    bool empty = false;
2015
10
    std::list<std::string> list;
2016
5
    std::list<std::string>::const_iterator i;
2017
5
    std::list<std::string>::const_iterator i_end;
2018
2019



60
    loadList("attackPriorityMobs", PriorityAttackMob)
2020



60
    loadList("attackMobs", AttackMob)
2021



60
    loadList("ignoreAttackMobs", IgnoreAttackMob)
2022
5
    if (!empty)
2023
    {
2024

20
        mAttackMobs.push_back("");
2025
25
        mAttackMobsSet.insert("");
2026
    }
2027
5
    empty = false;
2028
2029



60
    loadList("pickupItems", PickupItem)
2030



60
    loadList("ignorePickupItems", IgnorePickupItem)
2031
5
    if (!empty)
2032
    {
2033

20
        mPickupItems.push_back("");
2034
25
        mPickupItemsSet.insert("");
2035
    }
2036
2037
5
    rebuildAttackMobs();
2038
5
    rebuildPriorityAttackMobs();
2039
5
    rebuildPickupItems();
2040
5
}
2041
2042
5
void ActorManager::storeAttackList() const
2043
{
2044

25
    serverConfig.setValue("attackPriorityMobs", packList(mPriorityAttackMobs));
2045

25
    serverConfig.setValue("attackMobs", packList(mAttackMobs));
2046

25
    serverConfig.setValue("ignoreAttackMobs", packList(mIgnoreAttackMobs));
2047
2048

25
    serverConfig.setValue("pickupItems", packList(mPickupItems));
2049

25
    serverConfig.setValue("ignorePickupItems", packList(mIgnorePickupItems));
2050
5
}
2051
2052
bool ActorManager::checkForPickup(const FloorItem *const item) const
2053
{
2054
    if (mPickupItemsSet.find(std::string()) != mPickupItemsSet.end())
2055
    {
2056
        if (mIgnorePickupItemsSet.find(item->getName())
2057
            == mIgnorePickupItemsSet.end())
2058
        {
2059
            return true;
2060
        }
2061
    }
2062
    else if ((item != nullptr) && mPickupItemsSet.find(item->getName())
2063
             != mPickupItemsSet.end())
2064
    {
2065
        return true;
2066
    }
2067
    return false;
2068
}
2069
2070
bool ActorManager::checkDefaultPickup() const
2071
{
2072
    return mPickupItemsSet.find(std::string()) != mPickupItemsSet.end();
2073
}
2074
2075
void ActorManager::updateEffects(const std::map<BeingTypeId, int> &addEffects,
2076
                                 const std::set<BeingTypeId> &removeEffects)
2077
                                 const
2078
{
2079
    for_actorsm
2080
    {
2081
// disabled for performance
2082
//      if (reportTrue(*it == nullptr))
2083
//          continue;
2084
        if ((*it)->getType() != ActorType::Npc)
2085
            continue;
2086
        Being *const being = static_cast<Being*>(*it);
2087
        const BeingTypeId type = being->getSubType();
2088
        if (removeEffects.find(type) != removeEffects.end())
2089
            being->removeSpecialEffect();
2090
        const std::map<BeingTypeId, int>::const_iterator
2091
            idAdd = addEffects.find(type);
2092
        if (idAdd != addEffects.end())
2093
            being->addSpecialEffect((*idAdd).second);
2094
    }
2095
}
2096
2097
Being *ActorManager::cloneBeing(const Being *const srcBeing,
2098
                                const int dx, const int dy,
2099
                                const int id)
2100
{
2101
    returnNullptr(nullptr, srcBeing)
2102
    Being *const dstBeing = actorManager->createBeing(fromInt(
2103
        toInt(srcBeing->getId(), int) + id, BeingId),
2104
        ActorType::Player,
2105
        srcBeing->getSubType());
2106
    if (dstBeing == nullptr)
2107
        return nullptr;
2108
    dstBeing->setGender(srcBeing->getGender());
2109
    dstBeing->setAction(srcBeing->getCurrentAction(), 0);
2110
    dstBeing->setTileCoords(srcBeing->getTileX() + dx,
2111
        srcBeing->getTileY() + dy);
2112
    dstBeing->setName(srcBeing->getName());
2113
    dstBeing->setDirection(srcBeing->getDirection());
2114
    const int sz = CAST_S32(srcBeing->mSprites.size());
2115
    for (int slot = 0; slot < sz; slot ++)
2116
    {
2117
        const int spriteId = srcBeing->getSpriteID(slot);
2118
        const ItemColor color = srcBeing->getSpriteColor(slot);
2119
        dstBeing->setSpriteColorId(slot,
2120
            spriteId,
2121
            color);
2122
    }
2123
    const int hairSlot = charServerHandler->hairSprite();
2124
    const int hairStyle = -srcBeing->getSpriteID(hairSlot);
2125
    const ItemColor hairColor = srcBeing->getHairColor();
2126
    if (hairStyle != 0)
2127
    {
2128
        dstBeing->setSpriteColor(hairSlot,
2129
            hairStyle * -1,
2130
            ItemDB::get(-hairStyle).getDyeColorsString(hairColor));
2131
    }
2132
    else
2133
    {
2134
        dstBeing->unSetSprite(hairSlot);
2135
    }
2136
    dstBeing->setHairColor(hairColor);
2137
    return dstBeing;
2138
}
2139
2140
void ActorManager::updateBadges() const
2141
{
2142
    const BadgeDrawType::Type showBadges = static_cast<BadgeDrawType::Type>(
2143
        config.getIntValue("showBadges"));
2144
    Being::mShowBadges = showBadges;
2145
    Being::mVisibleNamePos = static_cast<VisibleNamePos::Type>(
2146
        config.getIntValue("visiblenamespos"));
2147
2148
    for_actors
2149
    {
2150
        ActorSprite *const actor = *it;
2151
        if (actor->getType() == ActorType::Player)
2152
        {
2153
            Being *const being = static_cast<Being*>(actor);
2154
            being->showBadges(showBadges != BadgeDrawType::Hide);
2155
        }
2156
    }
2157
}
2158
2159
void ActorManager::updateNameId(const std::string &name,
2160
                                const BeingId beingId)
2161
{
2162
    if (!mEnableIdCollecting)
2163
        return;
2164
    const int id = CAST_S32(beingId);
2165
    if ((id != 0) &&
2166
        (id < 2000000 ||
2167
        id >= 110000000))
2168
    {
2169
        return;
2170
    }
2171
2172
    if (mIdName.find(beingId) == mIdName.end() ||
2173
        mIdName[beingId].find(name) == mIdName[beingId].end())
2174
    {
2175
        mIdName[beingId].insert(name);
2176
        const std::string idStr = toString(id);
2177
        const std::string dateStr = getDateTimeString();
2178
        std::string dir;
2179
        if (beingId != BeingId_zero)
2180
        {
2181
            dir = pathJoin(settings.usersIdDir,
2182
                idStr,
2183
                stringToHexPath(name));
2184
            Files::saveTextFile(dir,
2185
                "info.txt",
2186
                (name + "\n").append(dateStr));
2187
        }
2188
2189
        dir = settings.usersDir;
2190
        dir.append(stringToHexPath(name));
2191
        Files::saveTextFile(dir,
2192
            "seen.txt",
2193
            (name + "\n").append(idStr).append("\n").append(dateStr));
2194
    }
2195
}
2196
2197
void ActorManager::updateSeenPlayers(const std::set<std::string>
2198
                                     &onlinePlayers)
2199
{
2200
    if (!mEnableIdCollecting)
2201
        return;
2202
2203
    FOR_EACH (std::set<std::string>::const_iterator, it, onlinePlayers)
2204
    {
2205
        const std::string name = *it;
2206
        if (findBeingByName(name, ActorType::Player) == nullptr)
2207
            updateNameId(name, BeingId_zero);
2208
    }
2209
}
2210
2211
std::string ActorManager::getSeenPlayerById(const BeingId id) const
2212
{
2213
    if (!mEnableIdCollecting)
2214
        return std::string();
2215
2216
    const IdNameMappingCIter it = mIdName.find(id);
2217
    if (it != mIdName.end())
2218
    {
2219
        if (!it->second.empty())
2220
            return *(it->second.begin());
2221
    }
2222
    return std::string();
2223
}
2224
2225
void ActorManager::removeRoom(const int chatId)
2226
{
2227
    for_actors
2228
    {
2229
        ActorSprite *const actor = *it;
2230
        if (actor->getType() == ActorType::Npc)
2231
        {
2232
            Being *const being = static_cast<Being*>(actor);
2233
            const ChatObject *const chat = being->getChat();
2234
            if ((chat != nullptr) && chat->chatId == chatId)
2235
            {
2236
                being->setChat(nullptr);
2237
            }
2238
        }
2239
    }
2240
}
2241
2242
void ActorManager::updateRoom(const ChatObject *const newChat)
2243
{
2244
    if (newChat == nullptr)
2245
        return;
2246
2247
    for_actors
2248
    {
2249
        const ActorSprite *const actor = *it;
2250
        if (actor->getType() == ActorType::Npc)
2251
        {
2252
            const Being *const being = static_cast<const Being*>(actor);
2253
            ChatObject *const chat = being->getChat();
2254
            if ((chat != nullptr) && chat->chatId == newChat->chatId)
2255
            {
2256
                chat->ownerId = newChat->ownerId;
2257
                chat->maxUsers = newChat->maxUsers;
2258
                chat->type = newChat->type;
2259
                chat->title = newChat->title;
2260
            }
2261
        }
2262
    }
2263
}
2264
2265
std::string ActorManager::findCharById(const int32_t id)
2266
{
2267
    const std::map<int32_t, std::string>::const_iterator it = mChars.find(id);
2268
    if (it == mChars.end())
2269
        return std::string();
2270
    return (*it).second;
2271
}
2272
2273
void ActorManager::addChar(const int32_t id,
2274
                           const std::string &name)
2275
{
2276
    mChars[id] = name;
2277
2278
    if (guiInput == nullptr)
2279
        return;
2280
2281
    if (localPlayer != nullptr)
2282
    {
2283
        Guild *const guild = localPlayer->getGuild();
2284
        if (guild != nullptr)
2285
        {
2286
            GuildMember *const member = guild->getMemberByCharId(id);
2287
            if (member != nullptr)
2288
                member->setName(name);
2289
        }
2290
    }
2291
    guiInput->simulateMouseMove();
2292
2
}