GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/actormanager.cpp Lines: 136 983 13.8 %
Date: 2019-03-21 Branches: 137 1422 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")
1854
        updateBadges();
1855
    else if (name == "visiblenamespos")
1856
        updateBadges();
1857
    else if (name == "enableIdCollecting")
1858
        mEnableIdCollecting = config.getBoolValue("enableIdCollecting");
1859
}
1860
1861
void ActorManager::removeAttackMob(const std::string &name)
1862
{
1863
    mPriorityAttackMobs.remove(name);
1864
    mAttackMobs.remove(name);
1865
    mIgnoreAttackMobs.remove(name);
1866
    mPriorityAttackMobsSet.erase(name);
1867
    mAttackMobsSet.erase(name);
1868
    mIgnoreAttackMobsSet.erase(name);
1869
    rebuildAttackMobs();
1870
    rebuildPriorityAttackMobs();
1871
    storeAttackList();
1872
}
1873
1874
void ActorManager::removePickupItem(const std::string &name)
1875
{
1876
    mPickupItems.remove(name);
1877
    mPickupItemsSet.erase(name);
1878
    mIgnorePickupItems.remove(name);
1879
    mIgnorePickupItemsSet.erase(name);
1880
    rebuildPickupItems();
1881
    storeAttackList();
1882
}
1883
1884
#define addMobToList(name, mob) \
1885
{\
1886
    const int sz = get##mob##sSize();\
1887
    if (sz > 0)\
1888
    {\
1889
        const int idx = get##mob##Index("");\
1890
        if (idx + 1 == sz)\
1891
        {\
1892
            std::list<std::string>::iterator itr = m##mob##s.end();\
1893
            -- itr;\
1894
            m##mob##s.insert(itr, name);\
1895
        }\
1896
        else\
1897
        {\
1898
            m##mob##s.push_back(name);\
1899
        }\
1900
    }\
1901
    else\
1902
    {\
1903
        m##mob##s.push_back(name);\
1904
    }\
1905
    m##mob##sSet.insert(name);\
1906
    rebuild##mob##s();\
1907
}
1908
1909
#define rebuildMobsList(mob) \
1910
{\
1911
    m##mob##sMap.clear();\
1912
    std::list<std::string>::const_iterator i = m##mob##s.begin();\
1913
    int cnt = 0;\
1914
    while (i != m##mob##s.end())\
1915
    {\
1916
        m##mob##sMap[*i] = cnt;\
1917
        ++ i;\
1918
        ++ cnt;\
1919
    }\
1920
}
1921
1922
void ActorManager::addAttackMob(const std::string &name)
1923
{
1924
    addMobToList(name, AttackMob)
1925
    rebuildPriorityAttackMobs();
1926
    storeAttackList();
1927
}
1928
1929
void ActorManager::addPriorityAttackMob(const std::string &name)
1930
{
1931
    addMobToList(name, PriorityAttackMob)
1932
    storeAttackList();
1933
}
1934
1935
void ActorManager::addIgnoreAttackMob(const std::string &name)
1936
{
1937
    mIgnoreAttackMobs.push_back(name);
1938
    mIgnoreAttackMobsSet.insert(name);
1939
    rebuildAttackMobs();
1940
    rebuildPriorityAttackMobs();
1941
    storeAttackList();
1942
}
1943
1944
void ActorManager::addPickupItem(const std::string &name)
1945
{
1946
    addMobToList(name, PickupItem)
1947
    rebuildPickupItems();
1948
    storeAttackList();
1949
}
1950
1951
void ActorManager::addIgnorePickupItem(const std::string &name)
1952
{
1953
    mIgnorePickupItems.push_back(name);
1954
    mIgnorePickupItemsSet.insert(name);
1955
    rebuildPickupItems();
1956
    storeAttackList();
1957
}
1958
1959
5
void ActorManager::rebuildPriorityAttackMobs()
1960
{
1961
25
    rebuildMobsList(PriorityAttackMob)
1962
5
}
1963
1964
5
void ActorManager::rebuildAttackMobs()
1965
{
1966
40
    rebuildMobsList(AttackMob)
1967
5
}
1968
1969
5
void ActorManager::rebuildPickupItems()
1970
{
1971
40
    rebuildMobsList(PickupItem)
1972
5
}
1973
1974
int ActorManager::getIndexByName(const std::string &name,
1975
                                 const StringIntMap &map)
1976
{
1977
    const StringIntMapCIter i = map.find(name);
1978
    if (i == map.end())
1979
        return -1;
1980
1981
    return (*i).second;
1982
}
1983
1984
int ActorManager::getPriorityAttackMobIndex(const std::string &name) const
1985
{
1986
    return getIndexByName(name, mPriorityAttackMobsMap);
1987
}
1988
1989
int ActorManager::getAttackMobIndex(const std::string &name) const
1990
{
1991
    return getIndexByName(name, mAttackMobsMap);
1992
}
1993
1994
int ActorManager::getPickupItemIndex(const std::string &name) const
1995
{
1996
    return getIndexByName(name, mPickupItemsMap);
1997
}
1998
1999
#define loadList(key, mob) \
2000
{\
2001
    list = unpackList(serverConfig.getValue(key, ""));\
2002
    i = list.begin();\
2003
    i_end = list.end();\
2004
    while (i != i_end)\
2005
    {\
2006
        if ((*i).empty())\
2007
            empty = true;\
2008
        m##mob##s.push_back(*i);\
2009
        m##mob##sSet.insert(*i);\
2010
        ++ i;\
2011
    }\
2012
}
2013
2014
5
void ActorManager::loadAttackList()
2015
{
2016
5
    bool empty = false;
2017
10
    std::list<std::string> list;
2018
5
    std::list<std::string>::const_iterator i;
2019
5
    std::list<std::string>::const_iterator i_end;
2020
2021



60
    loadList("attackPriorityMobs", PriorityAttackMob)
2022



60
    loadList("attackMobs", AttackMob)
2023



60
    loadList("ignoreAttackMobs", IgnoreAttackMob)
2024
5
    if (!empty)
2025
    {
2026

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



60
    loadList("pickupItems", PickupItem)
2032



60
    loadList("ignorePickupItems", IgnorePickupItem)
2033
5
    if (!empty)
2034
    {
2035

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

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

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

25
    serverConfig.setValue("ignoreAttackMobs", packList(mIgnoreAttackMobs));
2049
2050

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

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