GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/actormanager.cpp Lines: 136 977 13.9 %
Date: 2018-09-09 Branches: 137 1416 9.7 %

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-2018  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 "configuration.h"
27
#include "settings.h"
28
29
#include "being/localplayer.h"
30
#include "being/playerrelations.h"
31
32
#include "gui/sdlinput.h"
33
#include "gui/viewport.h"
34
35
#include "gui/widgets/tabs/chat/chattab.h"
36
37
#include "gui/windows/equipmentwindow.h"
38
#include "gui/windows/socialwindow.h"
39
#include "gui/windows/questswindow.h"
40
41
#include "fs/files.h"
42
43
#include "input/inputmanager.h"
44
45
#include "utils/checkutils.h"
46
#include "utils/foreach.h"
47
#include "utils/mathutils.h"
48
#include "utils/gettext.h"
49
50
#include "net/beinghandler.h"
51
#include "net/charserverhandler.h"
52
#include "net/packetlimiter.h"
53
#include "net/playerhandler.h"
54
#include "net/serverfeatures.h"
55
56
#include "resources/chatobject.h"
57
#include "resources/iteminfo.h"
58
59
#include "resources/map/map.h"
60
61
#include "resources/db/itemdb.h"
62
63
#ifdef TMWA_SUPPORT
64
#include "being/playerinfo.h"
65
66
#include "gui/windows/chatwindow.h"
67
68
#include "net/net.h"
69
#endif  // TMWA_SUPPORT
70
71
#include <algorithm>
72
73
#include "debug.h"
74
75
#define for_actors for (ActorSpritesConstIterator it = mActors.begin(), \
76
    it_fend = mActors.end(); it != it_fend; ++it)
77
78
#define for_actorsm for (ActorSpritesIterator it = mActors.begin(), \
79
    it_fend = mActors.end(); it != it_fend; ++it)
80
81
ActorManager *actorManager = nullptr;
82
83
class FindBeingFunctor final
84
{
85
    public:
86
        A_DEFAULT_COPY(FindBeingFunctor)
87
88
        bool operator() (const ActorSprite *const actor) const
89
        {
90
            if ((actor == nullptr)
91
                || actor->getType() == ActorType::FloorItem
92
                || actor->getType() == ActorType::Portal)
93
            {
94
                return false;
95
            }
96
            const Being *const b = static_cast<const Being *>(actor);
97
98
            const unsigned other_y = y
99
                + ((b->getType() == ActorType::Npc) ? 1 : 0);
100
            const Vector &pos = b->getPixelPositionF();
101
            // +++ probably here need use int positions and not float?
102
            // but for now correct int positions only in Being
103
            return CAST_U32(pos.x) / mapTileSize == x &&
104
                (CAST_U32(pos.y) / mapTileSize == y
105
                || CAST_U32(pos.y) / mapTileSize == other_y) &&
106
                b->isAlive() && (type == ActorType::Unknown
107
                || b->getType() == type);
108
        }
109
110
        uint16_t x, y;
111
        ActorTypeT type;
112
} beingActorFinder;
113
114
class FindBeingEqualFunctor final
115
{
116
    public:
117
        A_DEFAULT_COPY(FindBeingEqualFunctor)
118
119
        bool operator() (const Being *const being) const
120
        {
121
            if ((being == nullptr) || (findBeing == nullptr))
122
                return false;
123
            return being->getId() == findBeing->getId();
124
        }
125
126
        Being *findBeing;
127
} beingEqualActorFinder;
128
129
class SortBeingFunctor final
130
{
131
    public:
132
        A_DEFAULT_COPY(SortBeingFunctor)
133
134
        bool operator() (const Being *const being1,
135
                         const Being *const being2) const
136
        {
137
            if ((being1 == nullptr) || (being2 == nullptr))
138
                return false;
139
140
            if (priorityBeings != nullptr)
141
            {
142
                int w1 = defaultPriorityIndex;
143
                int w2 = defaultPriorityIndex;
144
                const StringIntMapCIter it1 = priorityBeings->find(
145
                    being1->getName());
146
                const StringIntMapCIter it2 = priorityBeings->find(
147
                    being2->getName());
148
                if (it1 != priorityBeings->end())
149
                    w1 = (*it1).second;
150
                if (it2 != priorityBeings->end())
151
                    w2 = (*it2).second;
152
153
                if (w1 != w2)
154
                    return w1 < w2;
155
            }
156
            if (being1->getDistance() != being2->getDistance())
157
            {
158
                if (specialDistance && being1->getDistance() <= 2
159
                    && being2->getDistance() <= attackRange
160
                    && being2->getDistance() > 2)
161
                {
162
                    return false;
163
                }
164
                else if (specialDistance && being2->getDistance() <= 2
165
                         && being1->getDistance() <= attackRange
166
                         && being1->getDistance() > 2)
167
                {
168
                    return true;
169
                }
170
                return being1->getDistance() < being2->getDistance();
171
            }
172
173
            const int d1 = abs(being1->getTileX() - x)
174
                + abs(being1->getTileY() - y);
175
            const int d2 = abs(being2->getTileX() - x)
176
                + abs(being2->getTileY() - y);
177
178
            if (d1 != d2)
179
                return d1 < d2;
180
            if (attackBeings != nullptr)
181
            {
182
                int w1 = defaultAttackIndex;
183
                int w2 = defaultAttackIndex;
184
                const StringIntMapCIter it1 = attackBeings->find(
185
                    being1->getName());
186
                const StringIntMapCIter it2 = attackBeings->find(
187
                    being2->getName());
188
                if (it1 != attackBeings->end())
189
                    w1 = (*it1).second;
190
                if (it2 != attackBeings->end())
191
                    w2 = (*it2).second;
192
193
                if (w1 != w2)
194
                    return w1 < w2;
195
            }
196
197
            return being1->getName() < being2->getName();
198
        }
199
        StringIntMap *attackBeings;
200
        StringIntMap *priorityBeings;
201
        int x;
202
        int y;
203
        int defaultAttackIndex;
204
        int defaultPriorityIndex;
205
        int attackRange;
206
        bool specialDistance;
207
} beingActorSorter;
208
209
5
ActorManager::ActorManager() :
210
    mActors(),
211
    mDeleteActors(),
212
    mActorsIdMap(),
213
    mIdName(),
214
    mBlockedBeings(),
215
    mChars(),
216
    mMap(nullptr),
217
#ifdef TMWA_SUPPORT
218
    mSpellHeal1(serverConfig.getValue("spellHeal1", "#lum")),
219
    mSpellHeal2(serverConfig.getValue("spellHeal2", "#inma")),
220
    mSpellItenplz(serverConfig.getValue("spellItenplz", "#itenplz")),
221
#endif  // TMWA_SUPPORT
222

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

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

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

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

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

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

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




235
    mIgnorePickupItemsSet()
242
{
243

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

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

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

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

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

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

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

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

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

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

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

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

1
        || (mCycleMonsters && type == ActorType::Monster)
1154
        || (mCycleNPC && type == ActorType::Npc));
1155
1156
    const bool filtered = allowSort == AllowSort_true
1157


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

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

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

12
        if ((being->getType() == ActorType::Player ||
1716
            (being->getType() == ActorType::Npc &&
1717

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



60
    loadList("attackPriorityMobs", PriorityAttackMob);
2025



60
    loadList("attackMobs", AttackMob);
2026



60
    loadList("ignoreAttackMobs", IgnoreAttackMob);
2027
5
    if (!empty)
2028
    {
2029

20
        mAttackMobs.push_back("");
2030
25
        mAttackMobsSet.insert("");
2031
    }
2032
5
    empty = false;
2033
2034



60
    loadList("pickupItems", PickupItem);
2035



60
    loadList("ignorePickupItems", IgnorePickupItem);
2036
5
    if (!empty)
2037
    {
2038

20
        mPickupItems.push_back("");
2039
25
        mPickupItemsSet.insert("");
2040
    }
2041
2042
5
    rebuildAttackMobs();
2043
5
    rebuildPriorityAttackMobs();
2044
5
    rebuildPickupItems();
2045
5
}
2046
2047
5
void ActorManager::storeAttackList() const
2048
{
2049

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

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

25
    serverConfig.setValue("ignoreAttackMobs", packList(mIgnoreAttackMobs));
2052
2053

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

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