GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/ea/playerrecv.cpp Lines: 1 109 0.9 %
Date: 2021-03-17 Branches: 0 83 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-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "net/ea/playerrecv.h"
25
26
#include "game.h"
27
#include "notifymanager.h"
28
#include "settings.h"
29
#include "soundmanager.h"
30
31
#include "being/localplayer.h"
32
#include "being/playerinfo.h"
33
34
#include "const/net/nostat.h"
35
36
#include "enums/resources/notifytypes.h"
37
38
#include "gui/viewport.h"
39
40
#include "gui/windows/statuswindow.h"
41
42
#include "input/inputmanager.h"
43
44
#include "resources/map/map.h"
45
46
#include "net/playerhandler.h"
47
48
#include "utils/stdmove.h"
49
#include "utils/stringutils.h"
50
51
#include "debug.h"
52
53
// Max. distance we are willing to scroll after a teleport;
54
// everything beyond will reset the port hard.
55
static const int MAP_TELEPORT_SCROLL_DISTANCE = 8;
56
57
namespace Ea
58
{
59
60
void PlayerRecv::processPlayerWarp(Net::MessageIn &msg)
61
{
62
    BLOCK_START("PlayerRecv::processPlayerWarp")
63
    std::string mapPath = msg.readString(16, "map name");
64
    int x = msg.readInt16("x");
65
    int y = msg.readInt16("y");
66
67
    logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y);
68
69
    if (localPlayer == nullptr)
70
        logger->log1("SMSG_PLAYER_WARP localPlayer null");
71
72
    /*
73
      * We must clear the local player's target *before* the call
74
      * to changeMap, as it deletes all beings.
75
      */
76
    if (localPlayer != nullptr)
77
        localPlayer->stopAttack(false);
78
79
    Game *const game = Game::instance();
80
    if (game == nullptr)
81
    {
82
        BLOCK_END("PlayerRecv::processPlayerWarp")
83
        return;
84
    }
85
86
    const std::string &currentMapName = game->getCurrentMapName();
87
    const bool sameMap = (currentMapName == mapPath);
88
89
    // Switch the actual map, deleting the previous one if necessary
90
    mapPath = mapPath.substr(0, mapPath.rfind('.'));
91
    game->changeMap(mapPath);
92
93
    int scrollOffsetX = 0;
94
    int scrollOffsetY = 0;
95
96
    if (localPlayer != nullptr)
97
    {
98
        const Map *const map = game->getCurrentMap();
99
        if (map != nullptr)
100
        {
101
            if (x >= map->getWidth())
102
                x = map->getWidth() - 1;
103
            if (y >= map->getHeight())
104
                y = map->getHeight() - 1;
105
            if (x < 0)
106
                x = 0;
107
            if (y < 0)
108
                y = 0;
109
            /* Scroll if neccessary */
110
            if (!sameMap
111
                || (abs(x - localPlayer->getTileX())
112
                > MAP_TELEPORT_SCROLL_DISTANCE)
113
                || (abs(y - localPlayer->getTileY())
114
                > MAP_TELEPORT_SCROLL_DISTANCE))
115
            {
116
                scrollOffsetX = (x - localPlayer->getTileX())
117
                    * map->getTileWidth();
118
                scrollOffsetY = (y - localPlayer->getTileY())
119
                    * map->getTileHeight();
120
            }
121
        }
122
123
        localPlayer->setAction(BeingAction::STAND, 0);
124
        localPlayer->setTileCoords(x, y);
125
        localPlayer->navigateClean();
126
        localPlayer->reset();
127
    }
128
129
    logger->log("Adjust scrolling by %d:%d", scrollOffsetX, scrollOffsetY);
130
131
    if (viewport != nullptr)
132
    {
133
        viewport->returnCamera();
134
        viewport->scrollBy(scrollOffsetX, scrollOffsetY);
135
    }
136
    BLOCK_END("PlayerRecv::processPlayerWarp")
137
}
138
139
void PlayerRecv::processPlayerStatUpdate1(Net::MessageIn &msg)
140
{
141
    BLOCK_START("PlayerRecv::processPlayerStatUpdate1")
142
    const int type = msg.readInt16("type");
143
    const int value = msg.readInt32("value");
144
    if (localPlayer == nullptr)
145
    {
146
        BLOCK_END("PlayerRecv::processPlayerStatUpdate1")
147
        return;
148
    }
149
150
    playerHandler->setStat(msg, type, value, NoStat, Notify_true);
151
    BLOCK_END("PlayerRecv::processPlayerStatUpdate1")
152
}
153
154
void PlayerRecv::processPlayerStatUpdate2(Net::MessageIn &msg)
155
{
156
    BLOCK_START("PlayerRecv::processPlayerStatUpdate2")
157
    const int type = msg.readInt16("type");
158
    const int value = msg.readInt32("value");
159
    playerHandler->setStat(msg, type, value, NoStat, Notify_true);
160
    BLOCK_END("PlayerRecv::processPlayerStatUpdate2")
161
}
162
163
void PlayerRecv::processPlayerStatUpdate3(Net::MessageIn &msg)
164
{
165
    BLOCK_START("PlayerRecv::processPlayerStatUpdate3")
166
    const int type = msg.readInt32("type");
167
    const int base = msg.readInt32("base");
168
    const int bonus = msg.readInt32("bonus");
169
170
    playerHandler->setStat(msg, type, base, bonus, Notify_false);
171
    BLOCK_END("PlayerRecv::processPlayerStatUpdate3")
172
}
173
174
void PlayerRecv::processPlayerStatUpdate4(Net::MessageIn &msg)
175
{
176
    BLOCK_START("PlayerRecv::processPlayerStatUpdate4")
177
    const uint16_t type = msg.readInt16("type");
178
    const uint8_t ok = msg.readUInt8("flag");
179
    const int value = msg.readUInt8("value");
180
181
    if (ok != 1)
182
    {
183
        const int oldValue = PlayerInfo::getStatBase(
184
            static_cast<AttributesT>(type));
185
        const int points = PlayerInfo::getAttribute(
186
            Attributes::PLAYER_CHAR_POINTS) + oldValue - value;
187
        PlayerInfo::setAttribute(Attributes::PLAYER_CHAR_POINTS,
188
            points,
189
            Notify_true);
190
        NotifyManager::notify(NotifyTypes::SKILL_RAISE_ERROR);
191
    }
192
193
    playerHandler->setStat(msg, type, value, NoStat, Notify_true);
194
    BLOCK_END("PlayerRecv::processPlayerStatUpdate4")
195
}
196
197
void PlayerRecv::processPlayerStatUpdate6(Net::MessageIn &msg)
198
{
199
    BLOCK_START("PlayerRecv::processPlayerStatUpdate6")
200
    const int type = msg.readInt16("type");
201
    const int value = msg.readUInt8("value");
202
    if (statusWindow != nullptr)
203
        playerHandler->setStat(msg, type, value, NoStat, Notify_true);
204
    BLOCK_END("PlayerRecv::processPlayerStatUpdate6")
205
}
206
207
void PlayerRecv::processPlayerArrowMessage(Net::MessageIn &msg)
208
{
209
    BLOCK_START("PlayerRecv::processPlayerArrowMessage")
210
    const int type = msg.readInt16("type");
211
    switch (type)
212
    {
213
        case 0:
214
            NotifyManager::notify(NotifyTypes::ARROWS_EQUIP_NEEDED);
215
            break;
216
        case 3:
217
            // arrows equiped
218
            break;
219
        default:
220
            UNIMPLEMENTEDPACKETFIELD(type);
221
            break;
222
    }
223
    BLOCK_END("PlayerRecv::processPlayerArrowMessage")
224
}
225
226
void PlayerRecv::processMapMusic(Net::MessageIn &msg)
227
{
228
    const int size = msg.readInt16("len") - 4;
229
    const std::string music = msg.readString(size, "name");
230
    soundManager.playMusic(music,
231
        SkipError_false);
232
233
    Map *const map = viewport->getMap();
234
    if (map != nullptr)
235
        map->setMusicFile(music);
236
}
237
238
void PlayerRecv::processMapMask(Net::MessageIn &msg)
239
{
240
    const int mask = msg.readInt32("mask");
241
    msg.readInt32("unused");
242
    Map *const map = Game::instance()->getCurrentMap();
243
    if (map != nullptr)
244
        map->setMask(mask);
245
}
246
247
void PlayerRecv::processPlayerClientCommand(Net::MessageIn &msg)
248
{
249
    const int sz = msg.readInt16("len") - 4;
250
    std::string command = msg.readString(sz, "command");
251
    std::string cmd;
252
    std::string args;
253
254
    if (settings.awayMode ||
255
        settings.pseudoAwayMode ||
256
        !settings.enableRemoteCommands)
257
    {
258
        return;
259
    }
260
261
    if (!parse2Str(command, cmd, args))
262
    {
263
        cmd = STD_MOVE(command);
264
        args.clear();
265
    }
266
    inputManager.executeRemoteChatCommand(cmd, args, nullptr);
267
}
268
269
2
}  // namespace Ea