GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/homunculusrecv.cpp Lines: 1 261 0.4 %
Date: 2021-03-17 Branches: 0 312 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "net/eathena/homunculusrecv.h"
23
24
#include "actormanager.h"
25
#include "notifymanager.h"
26
27
#include "being/homunculusinfo.h"
28
#include "being/playerinfo.h"
29
#include "being/localplayer.h"
30
31
#include "enums/resources/notifytypes.h"
32
33
#include "gui/windows/skilldialog.h"
34
35
#include "resources/iteminfo.h"
36
37
#include "resources/db/itemdb.h"
38
39
#include "net/messagein.h"
40
41
#include "utils/stringutils.h"
42
43
#include "debug.h"
44
45
namespace EAthena
46
{
47
48
void HomunculusRecv::processHomunculusSkills(Net::MessageIn &msg)
49
{
50
    if (skillDialog != nullptr)
51
        skillDialog->hideSkills(SkillOwner::Homunculus);
52
53
    const int count = (msg.readInt16("len") - 4) / 37;
54
    for (int f = 0; f < count; f ++)
55
    {
56
        const int skillId = msg.readInt16("skill id");
57
        const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
58
            msg.readInt16("inf"));
59
        msg.readInt16("unused");
60
        const int level = msg.readInt16("skill level");
61
        const int sp = msg.readInt16("sp");
62
        const int range = msg.readInt16("range");
63
        const std::string name = msg.readString(24, "skill name");
64
        const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
65
        PlayerInfo::setSkillLevel(skillId, level);
66
        if (skillDialog != nullptr)
67
        {
68
            if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
69
            {
70
                skillDialog->addSkill(SkillOwner::Homunculus,
71
                    skillId, name, level, range, up, inf, sp);
72
            }
73
        }
74
    }
75
    if (skillDialog != nullptr)
76
        skillDialog->updateModels();
77
}
78
79
void HomunculusRecv::processHomunculusData(Net::MessageIn &msg)
80
{
81
    if (actorManager == nullptr)
82
        return;
83
    msg.readUInt8("unused");
84
    const int cmd = msg.readUInt8("state");
85
    const BeingId id = msg.readBeingId("homunculus id");
86
    Being *const dstBeing = actorManager->findBeing(id);
87
    const int data = msg.readInt32("data");
88
    if (cmd == 0)  // pre init
89
    {
90
        HomunculusInfo *const info = new HomunculusInfo;
91
        info->id = id;
92
        PlayerInfo::setHomunculus(info);
93
        PlayerInfo::setHomunculusBeing(dstBeing);
94
        return;
95
    }
96
    HomunculusInfo *const info = PlayerInfo::getHomunculus();
97
    if (info == nullptr)
98
        return;
99
    switch (cmd)
100
    {
101
        case 1:  // intimacy
102
            info->intimacy = data;
103
            break;
104
        case 2:  // hunger
105
            info->hungry = data;
106
            break;
107
        case 3:  // accesory
108
            info->equip = data;
109
            break;
110
        default:
111
            break;
112
    }
113
}
114
115
void HomunculusRecv::processHomunculusInfo1(Net::MessageIn &msg)
116
{
117
    if (actorManager == nullptr)
118
        return;
119
    const std::string name = msg.readString(24, "name");
120
    msg.readUInt8("flags");  // 0x01 - renamed, 0x02 - vaporize, 0x04 - alive
121
    const int level = msg.readInt16("level");
122
    PlayerInfo::setStatBase(Attributes::HOMUN_LEVEL,
123
        level,
124
        Notify_true);
125
    const int hungry = msg.readInt16("hungry");
126
    const int intimacy = msg.readInt16("intimacy");
127
    const int equip = msg.readItemId("item id");
128
    PlayerInfo::setStatBase(Attributes::HOMUN_ATK,
129
        msg.readInt16("atk"),
130
        Notify_true);
131
    PlayerInfo::setStatBase(Attributes::HOMUN_MATK,
132
        msg.readInt16("matk"),
133
        Notify_true);
134
    PlayerInfo::setStatBase(Attributes::HOMUN_HIT,
135
        msg.readInt16("hit"),
136
        Notify_true);
137
    PlayerInfo::setStatBase(Attributes::HOMUN_CRIT,
138
        msg.readInt16("luk/3 or crit/10"),
139
        Notify_true);
140
    PlayerInfo::setStatBase(Attributes::HOMUN_DEF,
141
        msg.readInt16("def"),
142
        Notify_true);
143
    PlayerInfo::setStatBase(Attributes::HOMUN_MDEF,
144
        msg.readInt16("mdef"),
145
        Notify_true);
146
    PlayerInfo::setStatBase(Attributes::HOMUN_FLEE,
147
        msg.readInt16("flee"),
148
        Notify_true);
149
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_DELAY,
150
        msg.readInt16("attack speed"),
151
        Notify_true);
152
    PlayerInfo::setStatBase(Attributes::HOMUN_HP,
153
        msg.readInt16("hp"),
154
        Notify_true);
155
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_HP,
156
        msg.readInt16("max hp"),
157
        Notify_true);
158
    PlayerInfo::setStatBase(Attributes::HOMUN_MP,
159
        msg.readInt16("sp"),
160
        Notify_true);
161
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_MP,
162
        msg.readInt16("max sp"),
163
        Notify_true);
164
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP,
165
        msg.readInt32("exp"),
166
        Notify_true);
167
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP_NEEDED,
168
        msg.readInt32("next exp"),
169
        Notify_true);
170
    PlayerInfo::setStatBase(Attributes::HOMUN_SKILL_POINTS,
171
        msg.readInt16("skill points"),
172
        Notify_true);
173
    const int range = msg.readInt16("attack range");
174
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_RANGE,
175
        range,
176
        Notify_true);
177
178
    PlayerInfo::updateAttrs();
179
    HomunculusInfo *const info = PlayerInfo::getHomunculus();
180
    if (info == nullptr)
181
        return;
182
    Being *const dstBeing = actorManager->findBeing(info->id);
183
184
    info->name = name;
185
    info->level = level;
186
    info->range = range;
187
    info->hungry = hungry;
188
    info->intimacy = intimacy;
189
    info->equip = equip;
190
    PlayerInfo::setHomunculusBeing(dstBeing);
191
}
192
193
void HomunculusRecv::processHomunculusInfo2(Net::MessageIn &msg)
194
{
195
    if (actorManager == nullptr)
196
        return;
197
    const std::string name = msg.readString(24, "name");
198
    msg.readUInt8("flags");  // 0x01 - renamed, 0x02 - vaporize, 0x04 - alive
199
    const int level = msg.readInt16("level");
200
    PlayerInfo::setStatBase(Attributes::HOMUN_LEVEL,
201
        level,
202
        Notify_true);
203
    const int hungry = msg.readInt16("hungry");
204
    const int intimacy = msg.readInt16("intimacy");
205
    const int equip = msg.readItemId("item id");
206
    PlayerInfo::setStatBase(Attributes::HOMUN_ATK,
207
        msg.readInt16("atk"),
208
        Notify_true);
209
    PlayerInfo::setStatBase(Attributes::HOMUN_MATK,
210
        msg.readInt16("matk"),
211
        Notify_true);
212
    PlayerInfo::setStatBase(Attributes::HOMUN_HIT,
213
        msg.readInt16("hit"),
214
        Notify_true);
215
    PlayerInfo::setStatBase(Attributes::HOMUN_CRIT,
216
        msg.readInt16("luk/3 or crit/10"),
217
        Notify_true);
218
    PlayerInfo::setStatBase(Attributes::HOMUN_DEF,
219
        msg.readInt16("def"),
220
        Notify_true);
221
    PlayerInfo::setStatBase(Attributes::HOMUN_MDEF,
222
        msg.readInt16("mdef"),
223
        Notify_true);
224
    PlayerInfo::setStatBase(Attributes::HOMUN_FLEE,
225
        msg.readInt16("flee"),
226
        Notify_true);
227
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_DELAY,
228
        msg.readInt16("attack speed"),
229
        Notify_true);
230
    PlayerInfo::setStatBase(Attributes::HOMUN_HP,
231
        msg.readInt32("hp"),
232
        Notify_true);
233
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_HP,
234
        msg.readInt32("max hp"),
235
        Notify_true);
236
    PlayerInfo::setStatBase(Attributes::HOMUN_MP,
237
        msg.readInt16("sp"),
238
        Notify_true);
239
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_MP,
240
        msg.readInt16("max sp"),
241
        Notify_true);
242
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP,
243
        msg.readInt32("exp"),
244
        Notify_true);
245
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP_NEEDED,
246
        msg.readInt32("next exp"),
247
        Notify_true);
248
    PlayerInfo::setStatBase(Attributes::HOMUN_SKILL_POINTS,
249
        msg.readInt16("skill points"),
250
        Notify_true);
251
    const int range = msg.readInt16("attack range");
252
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_RANGE,
253
        range,
254
        Notify_true);
255
256
    PlayerInfo::updateAttrs();
257
    HomunculusInfo *const info = PlayerInfo::getHomunculus();
258
    if (info == nullptr)
259
        return;
260
    Being *const dstBeing = actorManager->findBeing(info->id);
261
262
    info->name = name;
263
    info->level = level;
264
    info->range = range;
265
    info->hungry = hungry;
266
    info->intimacy = intimacy;
267
    info->equip = equip;
268
    PlayerInfo::setHomunculusBeing(dstBeing);
269
}
270
271
void HomunculusRecv::processHomunculusInfo3(Net::MessageIn &msg)
272
{
273
    if (actorManager == nullptr)
274
        return;
275
    const std::string name = msg.readString(24, "name");
276
    msg.readUInt8("flags");  // 0x01 - renamed, 0x02 - vaporize, 0x04 - alive
277
    const int level = msg.readInt16("level");
278
    PlayerInfo::setStatBase(Attributes::HOMUN_LEVEL,
279
        level,
280
        Notify_true);
281
    const int hungry = msg.readInt16("hungry");
282
    const int intimacy = msg.readInt16("intimacy");
283
    PlayerInfo::setStatBase(Attributes::HOMUN_ATK,
284
        msg.readInt16("atk"),
285
        Notify_true);
286
    PlayerInfo::setStatBase(Attributes::HOMUN_MATK,
287
        msg.readInt16("matk"),
288
        Notify_true);
289
    PlayerInfo::setStatBase(Attributes::HOMUN_HIT,
290
        msg.readInt16("hit"),
291
        Notify_true);
292
    PlayerInfo::setStatBase(Attributes::HOMUN_CRIT,
293
        msg.readInt16("luk/3 or crit/10"),
294
        Notify_true);
295
    PlayerInfo::setStatBase(Attributes::HOMUN_DEF,
296
        msg.readInt16("def"),
297
        Notify_true);
298
    PlayerInfo::setStatBase(Attributes::HOMUN_MDEF,
299
        msg.readInt16("mdef"),
300
        Notify_true);
301
    PlayerInfo::setStatBase(Attributes::HOMUN_FLEE,
302
        msg.readInt16("flee"),
303
        Notify_true);
304
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_DELAY,
305
        msg.readInt16("attack speed"),
306
        Notify_true);
307
    PlayerInfo::setStatBase(Attributes::HOMUN_HP,
308
        msg.readInt32("hp"),
309
        Notify_true);
310
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_HP,
311
        msg.readInt32("max hp"),
312
        Notify_true);
313
    PlayerInfo::setStatBase(Attributes::HOMUN_MP,
314
        msg.readInt16("sp"),
315
        Notify_true);
316
    PlayerInfo::setStatBase(Attributes::HOMUN_MAX_MP,
317
        msg.readInt16("max sp"),
318
        Notify_true);
319
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP,
320
        msg.readInt32("exp"),
321
        Notify_true);
322
    PlayerInfo::setStatBase(Attributes::HOMUN_EXP_NEEDED,
323
        msg.readInt32("next exp"),
324
        Notify_true);
325
    PlayerInfo::setStatBase(Attributes::HOMUN_SKILL_POINTS,
326
        msg.readInt16("skill points"),
327
        Notify_true);
328
    const int range = msg.readInt16("attack range");
329
    PlayerInfo::setStatBase(Attributes::HOMUN_ATTACK_RANGE,
330
        range,
331
        Notify_true);
332
333
    PlayerInfo::updateAttrs();
334
    HomunculusInfo *const info = PlayerInfo::getHomunculus();
335
    if (info == nullptr)
336
        return;
337
    Being *const dstBeing = actorManager->findBeing(info->id);
338
339
    info->name = name;
340
    info->level = level;
341
    info->range = range;
342
    info->hungry = hungry;
343
    info->intimacy = intimacy;
344
    info->equip = 0;
345
    PlayerInfo::setHomunculusBeing(dstBeing);
346
}
347
348
void HomunculusRecv::processHomunculusSkillUp(Net::MessageIn &msg)
349
{
350
    const int skillId = msg.readInt16("skill id");
351
    const int level = msg.readInt16("level");
352
    const int sp = msg.readInt16("sp");
353
    const int range = msg.readInt16("range");
354
    const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
355
356
    if (skillDialog != nullptr && PlayerInfo::getSkillLevel(skillId) != level)
357
        skillDialog->playUpdateEffect(skillId);
358
    PlayerInfo::setSkillLevel(skillId, level);
359
    if (skillDialog != nullptr)
360
    {
361
        if (!skillDialog->updateSkill(skillId, range,
362
            up, SkillType::Unknown, sp))
363
        {
364
            skillDialog->addSkill(SkillOwner::Homunculus,
365
                skillId, "", level,
366
                range, up, SkillType::Unknown, sp);
367
        }
368
    }
369
}
370
371
void HomunculusRecv::processHomunculusFood(Net::MessageIn &msg)
372
{
373
    const int flag = msg.readUInt8("fail");
374
    const int itemId = msg.readItemId("food id");
375
    if (flag != 0)
376
    {
377
        NotifyManager::notify(NotifyTypes::HOMUNCULUS_FEED_OK);
378
    }
379
    else
380
    {
381
        const std::string name = strprintf("[@@%d|%s@@]", itemId,
382
            ItemDB::get(itemId).getName().c_str());
383
        NotifyManager::notify(NotifyTypes::HOMUNCULUS_FEED_FAIL, name);
384
    }
385
}
386
387
void HomunculusRecv::processHomunculusExp(Net::MessageIn &msg)
388
{
389
    const int exp = msg.readInt32("exp");
390
    msg.readInt32("unused");
391
    if (localPlayer != nullptr)
392
        localPlayer->addHomunXpMessage(exp);
393
}
394
395
2
}  // namespace EAthena