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/mercenaryrecv.h"
23
24 #include "actormanager.h"
25 #include "notifymanager.h"
26
27 #include "being/localplayer.h"
28 #include "being/mercenaryinfo.h"
29 #include "being/playerinfo.h"
30
31 #include "enums/resources/notifytypes.h"
32
33 #include "gui/windows/skilldialog.h"
34
35 #include "net/messagein.h"
36
37 #include "net/eathena/sp.h"
38
39 #include "utils/checkutils.h"
40
41 #include "debug.h"
42
43 namespace EAthena
44 {
45
46 #define setMercStat(sp, stat) \
47 case sp: \
48 PlayerInfo::setStatBase(stat, \
49 val, \
50 Notify_true); \
51 break
52
processMercenaryUpdate(Net::MessageIn & msg)53 void MercenaryRecv::processMercenaryUpdate(Net::MessageIn &msg)
54 {
55 const int sp = msg.readInt16("type");
56 const int val = msg.readInt32("value");
57 switch (sp)
58 {
59 setMercStat(Sp::ATK1, Attributes::MERC_ATK);
60 setMercStat(Sp::MATK1, Attributes::MERC_MATK);
61 setMercStat(Sp::HIT, Attributes::MERC_HIT);
62 setMercStat(Sp::CRITICAL, Attributes::MERC_CRIT);
63 setMercStat(Sp::DEF1, Attributes::MERC_DEF);
64 setMercStat(Sp::MDEF1, Attributes::MERC_MDEF);
65 setMercStat(Sp::MERCFLEE, Attributes::MERC_FLEE);
66 setMercStat(Sp::ASPD, Attributes::MERC_ATTACK_DELAY);
67 setMercStat(Sp::HP, Attributes::MERC_HP);
68 setMercStat(Sp::MAXHP, Attributes::MERC_MAX_HP);
69 setMercStat(Sp::SP, Attributes::MERC_MP);
70 setMercStat(Sp::MAXSP, Attributes::MERC_MAX_MP);
71 setMercStat(Sp::MERCKILLS, Attributes::MERC_KILLS);
72 setMercStat(Sp::MERCFAITH, Attributes::MERC_FAITH);
73 default:
74 reportAlways("Unknown mercenary stat %d",
75 sp)
76 break;
77 }
78 }
79
processMercenaryInfo(Net::MessageIn & msg)80 void MercenaryRecv::processMercenaryInfo(Net::MessageIn &msg)
81 {
82 if (actorManager == nullptr)
83 return;
84 // +++ need create if need mercenary being and update stats
85 Being *const dstBeing = actorManager->findBeing(
86 msg.readBeingId("being id"));
87 PlayerInfo::setStatBase(Attributes::MERC_ATK,
88 msg.readInt16("atk"),
89 Notify_true);
90 PlayerInfo::setStatBase(Attributes::MERC_MATK,
91 msg.readInt16("matk"),
92 Notify_true);
93 PlayerInfo::setStatBase(Attributes::MERC_HIT,
94 msg.readInt16("hit"),
95 Notify_true);
96 PlayerInfo::setStatBase(Attributes::MERC_CRIT,
97 msg.readInt16("crit/10"),
98 Notify_true);
99 PlayerInfo::setStatBase(Attributes::MERC_DEF,
100 msg.readInt16("def"),
101 Notify_true);
102 PlayerInfo::setStatBase(Attributes::MERC_MDEF,
103 msg.readInt16("mdef"),
104 Notify_true);
105 PlayerInfo::setStatBase(Attributes::MERC_FLEE,
106 msg.readInt16("flee"),
107 Notify_true);
108 PlayerInfo::setStatBase(Attributes::MERC_ATTACK_DELAY,
109 msg.readInt16("attack speed"),
110 Notify_true);
111 const std::string name = msg.readString(24, "name");
112 const int level = msg.readInt16("level");
113 PlayerInfo::setStatBase(Attributes::MERC_LEVEL,
114 level,
115 Notify_true);
116 PlayerInfo::setStatBase(Attributes::MERC_HP,
117 msg.readInt32("hp"),
118 Notify_true);
119 PlayerInfo::setStatBase(Attributes::MERC_MAX_HP,
120 msg.readInt32("max hp"),
121 Notify_true);
122 PlayerInfo::setStatBase(Attributes::MERC_MP,
123 msg.readInt32("sp"),
124 Notify_true);
125 PlayerInfo::setStatBase(Attributes::MERC_MAX_MP,
126 msg.readInt32("max sp"),
127 Notify_true);
128 PlayerInfo::setStatBase(Attributes::MERC_EXPIRE,
129 msg.readInt32("expire time"),
130 Notify_true);
131 PlayerInfo::setStatBase(Attributes::MERC_FAITH,
132 msg.readInt16("faith"),
133 Notify_true);
134 PlayerInfo::setStatBase(Attributes::MERC_CALLS,
135 msg.readInt32("calls"),
136 Notify_true);
137 PlayerInfo::setStatBase(Attributes::MERC_KILLS,
138 msg.readInt32("kills"),
139 Notify_true);
140 const int range = msg.readInt16("attack range");
141 PlayerInfo::setStatBase(Attributes::MERC_ATTACK_RANGE,
142 range,
143 Notify_true);
144 PlayerInfo::updateAttrs();
145
146 if ((dstBeing != nullptr) && (localPlayer != nullptr))
147 {
148 MercenaryInfo *const mercenary = new MercenaryInfo;
149 mercenary->id = dstBeing->getId();
150 mercenary->name = name;
151 mercenary->level = level;
152 mercenary->range = range;
153 PlayerInfo::setMercenary(mercenary);
154 PlayerInfo::setMercenaryBeing(dstBeing);
155 }
156 }
157
processMercenarySkills(Net::MessageIn & msg)158 void MercenaryRecv::processMercenarySkills(Net::MessageIn &msg)
159 {
160 if (skillDialog != nullptr)
161 skillDialog->hideSkills(SkillOwner::Mercenary);
162 const int count = (msg.readInt16("len") - 4) / 37;
163 for (int f = 0; f < count; f ++)
164 {
165 const int skillId = msg.readInt16("skill id");
166 const SkillType::SkillType inf = static_cast<SkillType::SkillType>(
167 msg.readInt32("inf"));
168 const int level = msg.readInt16("skill level");
169 const int sp = msg.readInt16("sp");
170 const int range = msg.readInt16("range");
171 const std::string name = msg.readString(24, "skill name");
172 const Modifiable up = fromBool(msg.readUInt8("up flag"), Modifiable);
173 PlayerInfo::setSkillLevel(skillId, level);
174 if (skillDialog != nullptr)
175 {
176 if (!skillDialog->updateSkill(skillId, range, up, inf, sp))
177 {
178 skillDialog->addSkill(SkillOwner::Mercenary,
179 skillId, name, level, range, up, inf, sp);
180 }
181 }
182 }
183 if (skillDialog != nullptr)
184 skillDialog->updateModels();
185 }
186
handleMercenaryMessage(const int cmd)187 void MercenaryRecv::handleMercenaryMessage(const int cmd)
188 {
189 PlayerInfo::setMercenary(nullptr);
190 if (skillDialog != nullptr)
191 {
192 skillDialog->hideSkills(SkillOwner::Mercenary);
193 skillDialog->updateModels();
194 }
195
196 switch (cmd)
197 {
198 case 0:
199 NotifyManager::notify(NotifyTypes::MERCENARY_EXPIRED);
200 break;
201 case 1:
202 NotifyManager::notify(NotifyTypes::MERCENARY_KILLED);
203 break;
204 case 2:
205 NotifyManager::notify(NotifyTypes::MERCENARY_FIRED);
206 break;
207 case 3:
208 NotifyManager::notify(NotifyTypes::MERCENARY_RUN);
209 break;
210 default:
211 NotifyManager::notify(NotifyTypes::MERCENARY_UNKNOWN);
212 break;
213 }
214 }
215
216 } // namespace EAthena
217