GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/ea/beingrecv.cpp Lines: 1 217 0.5 %
Date: 2017-11-29 Branches: 0 223 0.0 %

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-2017  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 "net/ea/beingrecv.h"
24
25
#include "actormanager.h"
26
#include "configuration.h"
27
#include "game.h"
28
#include "notifymanager.h"
29
#include "party.h"
30
31
#include "being/localplayer.h"
32
#include "being/playerrelation.h"
33
#include "being/playerrelations.h"
34
35
#include "enums/resources/notifytypes.h"
36
37
#include "enums/resources/map/mapitemtype.h"
38
39
#include "gui/viewport.h"
40
41
#include "gui/windows/socialwindow.h"
42
43
#include "utils/foreach.h"
44
45
#include "resources/map/map.h"
46
47
#include "net/messagein.h"
48
#include "net/serverfeatures.h"
49
50
#include "debug.h"
51
52
namespace Ea
53
{
54
55
namespace BeingRecv
56
{
57
    bool mSync = false;
58
    BeingId mSpawnId = BeingId_zero;
59
}  // namespace BeingRecv
60
61
void BeingRecv::processBeingRemove(Net::MessageIn &msg)
62
{
63
    BLOCK_START("BeingRecv::processBeingRemove")
64
    if ((actorManager == nullptr) || (localPlayer == nullptr))
65
    {
66
        BLOCK_END("BeingRecv::processBeingRemove")
67
        return;
68
    }
69
70
    // A being should be removed or has died
71
72
    const BeingId id = msg.readBeingId("being id");
73
    const uint8_t type = msg.readUInt8("remove flag");
74
    Being *const dstBeing = actorManager->findBeing(id);
75
    if (dstBeing == nullptr)
76
    {
77
        BLOCK_END("BeingRecv::processBeingRemove")
78
        return;
79
    }
80
81
    localPlayer->followMoveTo(dstBeing, localPlayer->getNextDestX(),
82
        localPlayer->getNextDestY());
83
84
    // If this is player's current target, clear it.
85
    if (dstBeing == localPlayer->getTarget())
86
        localPlayer->stopAttack(true);
87
88
    if (type == 1U)
89
    {
90
        if (dstBeing->getCurrentAction() != BeingAction::DEAD)
91
        {
92
            dstBeing->setAction(BeingAction::DEAD, 0);
93
            dstBeing->recalcSpritesOrder();
94
        }
95
    }
96
    else if (type == 0U && dstBeing->getType() == ActorType::Npc)
97
    {
98
        const BeingInfo *const info = dstBeing->getInfo();
99
        if ((info == nullptr) || (info->getAllowDelete() != 0))
100
            actorManager->destroy(dstBeing);
101
    }
102
    else
103
    {
104
        if (dstBeing->getType() == ActorType::Player)
105
        {
106
            if (socialWindow != nullptr)
107
                socialWindow->updateActiveList();
108
            const std::string name = dstBeing->getName();
109
            if (!name.empty() && config.getBoolValue("logPlayerActions"))
110
            {
111
                switch (type)
112
                {
113
                    case 0:
114
                        dstBeing->serverRemove();
115
                        break;
116
                    case 1:
117
                        NotifyManager::notify(
118
                            NotifyTypes::BEING_REMOVE_DIED,
119
                            name);
120
                        break;
121
                    case 2:
122
                        NotifyManager::notify(
123
                            NotifyTypes::BEING_REMOVE_LOGGED_OUT,
124
                            name);
125
                        break;
126
                    case 3:
127
                        NotifyManager::notify(
128
                            NotifyTypes::BEING_REMOVE_WARPED,
129
                            name);
130
                        break;
131
                    case 4:
132
                        NotifyManager::notify(
133
                            NotifyTypes::BEING_REMOVE_TRICK_DEAD,
134
                            name);
135
                        break;
136
                    default:
137
                        NotifyManager::notify(
138
                            NotifyTypes::BEING_REMOVE_UNKNOWN,
139
                            name);
140
                        break;
141
                }
142
            }
143
        }
144
        actorManager->destroy(dstBeing);
145
    }
146
    BLOCK_END("BeingRecv::processBeingRemove")
147
}
148
149
void BeingRecv::processBeingAction(Net::MessageIn &msg)
150
{
151
    BLOCK_START("BeingRecv::processBeingAction")
152
    if (actorManager == nullptr)
153
    {
154
        BLOCK_END("BeingRecv::processBeingAction")
155
        return;
156
    }
157
158
    Being *const srcBeing = actorManager->findBeing(
159
        msg.readBeingId("src being id"));
160
    Being *const dstBeing = actorManager->findBeing(
161
        msg.readBeingId("dst being id"));
162
163
    msg.readInt32("tick");
164
    const int srcSpeed = msg.readInt32("src speed");
165
    msg.readInt32("dst speed");
166
    const int param1 = msg.readInt16("param1");
167
    msg.readInt16("param 2");
168
    const AttackTypeT type = static_cast<AttackTypeT>(
169
        msg.readUInt8("type"));
170
    msg.readInt16("param 3");
171
172
    switch (type)
173
    {
174
        case AttackType::HIT:  // Damage
175
        case AttackType::CRITICAL:  // Critical Damage
176
        case AttackType::MULTI:  // Critical Damage
177
        case AttackType::REFLECT:  // Reflected Damage
178
        case AttackType::FLEE:  // Lucky Dodge
179
            if (srcBeing != nullptr)
180
            {
181
                if (srcSpeed != 0 && srcBeing->getType() == ActorType::Player)
182
                    srcBeing->setAttackDelay(srcSpeed);
183
                // attackid=1, type
184
                srcBeing->handleAttack(dstBeing, param1, 1);
185
                if (srcBeing->getType() == ActorType::Player)
186
                    srcBeing->setAttackTime();
187
            }
188
            if (dstBeing != nullptr)
189
            {
190
                // level not present, using 1
191
                dstBeing->takeDamage(srcBeing, param1,
192
                    static_cast<AttackTypeT>(type), 1);
193
            }
194
            break;
195
196
        case AttackType::PICKUP:
197
            break;
198
            // tmw server can send here garbage?
199
//            if (srcBeing)
200
//                srcBeing->setAction(BeingAction::DEAD, 0);
201
202
        case AttackType::SIT:
203
            if (srcBeing != nullptr)
204
            {
205
                srcBeing->setAction(BeingAction::SIT, 0);
206
                if (srcBeing->getType() == ActorType::Player)
207
                {
208
                    srcBeing->setMoveTime();
209
                    if (localPlayer != nullptr)
210
                        localPlayer->imitateAction(srcBeing, BeingAction::SIT);
211
                }
212
            }
213
            break;
214
215
        case AttackType::STAND:
216
            if (srcBeing != nullptr)
217
            {
218
                srcBeing->setAction(BeingAction::STAND, 0);
219
                if (srcBeing->getType() == ActorType::Player)
220
                {
221
                    srcBeing->setMoveTime();
222
                    if (localPlayer != nullptr)
223
                    {
224
                        localPlayer->imitateAction(srcBeing,
225
                            BeingAction::STAND);
226
                    }
227
                }
228
            }
229
            break;
230
        default:
231
        case AttackType::SPLASH:
232
        case AttackType::SKILL:
233
        case AttackType::REPEATE:
234
        case AttackType::MULTI_REFLECT:
235
        case AttackType::TOUCH_SKILL:
236
        case AttackType::MISS:
237
        case AttackType::SKILLMISS:
238
            UNIMPLEMENTEDPACKETFIELD(CAST_S32(type));
239
            break;
240
    }
241
    BLOCK_END("BeingRecv::processBeingAction")
242
}
243
244
void BeingRecv::processBeingEmotion(Net::MessageIn &msg)
245
{
246
    BLOCK_START("BeingRecv::processBeingEmotion")
247
    if ((localPlayer == nullptr) || (actorManager == nullptr))
248
    {
249
        BLOCK_END("BeingRecv::processBeingEmotion")
250
        return;
251
    }
252
253
    Being *const dstBeing = actorManager->findBeing(
254
        msg.readBeingId("being id"));
255
    if (dstBeing == nullptr)
256
    {
257
        DEBUGLOGSTR("invisible player?");
258
        msg.readUInt8("emote");
259
        BLOCK_END("BeingRecv::processBeingEmotion")
260
        return;
261
    }
262
263
    const uint8_t emote = msg.readUInt8("emote");
264
    if ((emote != 0u) &&
265
        playerRelations.hasPermission(dstBeing, PlayerRelation::EMOTE))
266
    {
267
        dstBeing->setEmote(emote, 0);
268
        localPlayer->imitateEmote(dstBeing, emote);
269
    }
270
    if (dstBeing->getType() == ActorType::Player)
271
        dstBeing->setOtherTime();
272
    BLOCK_END("BeingRecv::processBeingEmotion")
273
}
274
275
void BeingRecv::processNameResponse(Net::MessageIn &msg)
276
{
277
    BLOCK_START("BeingRecv::processNameResponse")
278
    if ((localPlayer == nullptr) || (actorManager == nullptr))
279
    {
280
        BLOCK_END("BeingRecv::processNameResponse")
281
        return;
282
    }
283
284
    const BeingId beingId = msg.readBeingId("being id");
285
    const std::string name = msg.readString(24, "name");
286
    Being *const dstBeing = actorManager->findBeing(beingId);
287
288
    actorManager->updateNameId(name, beingId);
289
290
    if (dstBeing != nullptr)
291
    {
292
        if (beingId == localPlayer->getId())
293
        {
294
            localPlayer->pingResponse();
295
        }
296
        else
297
        {
298
            if (dstBeing->getType() != ActorType::Portal)
299
            {
300
                dstBeing->setName(name);
301
            }
302
            else if (viewport != nullptr)
303
            {
304
                Map *const map = viewport->getMap();
305
                if (map != nullptr)
306
                {
307
                    map->addPortalTile(name, MapItemType::PORTAL,
308
                        dstBeing->getTileX(), dstBeing->getTileY());
309
                }
310
            }
311
            dstBeing->updateGuild();
312
            dstBeing->addToCache();
313
314
            if (dstBeing->getType() == ActorType::Player)
315
                dstBeing->updateColors();
316
317
            if (localPlayer != nullptr)
318
            {
319
                const Party *const party = localPlayer->getParty();
320
                if (party != nullptr && party->isMember(dstBeing->getId()))
321
                {
322
                    PartyMember *const member = party->getMember(
323
                        dstBeing->getId());
324
325
                    if (member != nullptr)
326
                        member->setName(dstBeing->getName());
327
                }
328
                localPlayer->checkNewName(dstBeing);
329
            }
330
            BLOCK_END("BeingRecv::processNameResponse")
331
            return;
332
        }
333
    }
334
    BLOCK_END("BeingRecv::processNameResponse")
335
}
336
337
void BeingRecv::processPlayerStop(Net::MessageIn &msg)
338
{
339
    BLOCK_START("BeingRecv::processPlayerStop")
340
    if ((actorManager == nullptr) || (localPlayer == nullptr))
341
    {
342
        BLOCK_END("BeingRecv::processPlayerStop")
343
        return;
344
    }
345
346
    const BeingId id = msg.readBeingId("account id");
347
348
    if (mSync || id != localPlayer->getId())
349
    {
350
        Being *const dstBeing = actorManager->findBeing(id);
351
        if (dstBeing != nullptr)
352
        {
353
            const uint16_t x = msg.readInt16("x");
354
            const uint16_t y = msg.readInt16("y");
355
            dstBeing->setTileCoords(x, y);
356
            if (dstBeing->getCurrentAction() == BeingAction::MOVE)
357
                dstBeing->setAction(BeingAction::STAND, 0);
358
            BLOCK_END("BeingRecv::processPlayerStop")
359
            return;
360
        }
361
    }
362
    msg.readInt16("x");
363
    msg.readInt16("y");
364
    BLOCK_END("BeingRecv::processPlayerStop")
365
}
366
367
void BeingRecv::processPlayerMoveToAttack(Net::MessageIn &msg)
368
{
369
    BLOCK_START("BeingRecv::processPlayerStop")
370
    msg.readInt32("target id");
371
    msg.readInt16("target x");
372
    msg.readInt16("target y");
373
    msg.readInt16("x");
374
    msg.readInt16("y");
375
    msg.readInt16("attack range");
376
377
    if (localPlayer != nullptr)
378
        localPlayer->fixAttackTarget();
379
    BLOCK_END("BeingRecv::processPlayerStop")
380
}
381
382
void BeingRecv::processSkillNoDamage(Net::MessageIn &msg)
383
{
384
    const int id = msg.readInt16("skill id");
385
    int heal;
386
    if (msg.getVersion() >= 20131223)
387
        heal = msg.readInt32("heal");
388
    else
389
        heal = msg.readInt16("heal");
390
    Being *const dstBeing = actorManager->findBeing(
391
        msg.readBeingId("dst being id"));
392
    Being *const srcBeing = actorManager->findBeing(
393
        msg.readBeingId("src being id"));
394
    msg.readUInt8("fail");
395
396
    if (srcBeing != nullptr)
397
        srcBeing->handleSkill(dstBeing, heal, id, 1);
398
}
399
400
void BeingRecv::processPvpMapMode(Net::MessageIn &msg)
401
{
402
    BLOCK_START("BeingRecv::processPvpMapMode")
403
    const Game *const game = Game::instance();
404
    if (game == nullptr)
405
    {
406
        BLOCK_END("BeingRecv::processPvpMapMode")
407
        return;
408
    }
409
410
    Map *const map = game->getCurrentMap();
411
    if (map != nullptr)
412
        map->setPvpMode(msg.readInt16("pvp mode"));
413
    BLOCK_END("BeingRecv::processPvpMapMode")
414
}
415
416
void BeingRecv::processBeingMove3(Net::MessageIn &msg)
417
{
418
    BLOCK_START("BeingRecv::processBeingMove3")
419
    if ((actorManager == nullptr) || !serverFeatures->haveMove3())
420
    {
421
        BLOCK_END("BeingRecv::processBeingMove3")
422
        return;
423
    }
424
425
    static const int16_t dirx[8] = {0, -1, -1, -1,  0,  1, 1, 1};
426
    static const int16_t diry[8] = {1,  1,  0, -1, -1, -1, 0, 1};
427
428
    const int len = msg.readInt16("len") - 14;
429
    Being *const dstBeing = actorManager->findBeing(
430
        msg.readBeingId("being id"));
431
    if (dstBeing == nullptr ||
432
        dstBeing == localPlayer)
433
    {
434
        DEBUGLOGSTR("invisible player?");
435
        msg.readInt16("speed");
436
        msg.readInt16("x");
437
        msg.readInt16("y");
438
        unsigned char *bytes = msg.readBytes(len, "moving path");
439
        delete [] bytes;
440
        BLOCK_END("BeingRecv::processBeingMove3")
441
        return;
442
    }
443
    const int16_t speed = msg.readInt16("speed");
444
    dstBeing->setWalkSpeed(speed);
445
    const int16_t x = msg.readInt16("x");
446
    const int16_t y = msg.readInt16("y");
447
    const unsigned char *moves = msg.readBytes(len, "moving path");
448
449
    Path path;
450
    if (moves != nullptr)
451
    {
452
        int x2 = dstBeing->getCachedX();
453
        int y2 = dstBeing->getCachedY();
454
        Path path2;
455
        path2.push_back(Position(x2, y2));
456
        for (int f = len - 1; f >= 0; f --)
457
        {
458
            const unsigned char dir = moves[f];
459
            if (dir <= 7)
460
            {
461
                x2 -= dirx[dir];
462
                y2 -= diry[dir];
463
                path2.push_back(Position(x2, y2));
464
                if (x2 == x && y2 == y)
465
                    break;
466
            }
467
            else
468
            {
469
                logger->log("bad move packet: %d", dir);
470
            }
471
        }
472
473
        if (!path2.empty())
474
        {
475
            const Position &pos = path2.back();
476
            if (x != pos.x ||
477
                y != pos.y)
478
            {
479
                dstBeing->setTileCoords(pos.x, pos.y);
480
            }
481
        }
482
483
        path2.pop_back();
484
        FOR_EACHR (PathRIterator, it, path2)
485
        {
486
            path.push_back(*it);
487
        }
488
        delete [] moves;
489
    }
490
491
    if (path.empty())
492
        return;
493
494
    dstBeing->setAction(BeingAction::STAND, 0);
495
    dstBeing->setTileCoords(x, y);
496
    dstBeing->setPath(path);
497
    BLOCK_END("BeingRecv::processBeingMove3")
498
}
499
500
Being *BeingRecv::createBeing(const BeingId id,
501
                              const int job)
502
{
503
    if (actorManager == nullptr)
504
        return nullptr;
505
506
    ActorTypeT type = ActorType::Unknown;
507
    if (job <= 25 || (job >= 4001 && job <= 4049))
508
        type = ActorType::Player;
509
    else if (job >= 46 && job <= 1000)
510
        type = ActorType::Npc;
511
    else if (job > 1000 && job <= 2000)
512
        type = ActorType::Monster;
513
    else if (job == 45)
514
        type = ActorType::Portal;
515
516
    return actorManager->createBeing(
517
        id, type, fromInt(job, BeingTypeId));
518
}
519
520
4
}  // namespace Ea