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/tmwa/beingrecv.h" |
25 |
|
|
|
26 |
|
|
#include "actormanager.h" |
27 |
|
|
#include "configuration.h" |
28 |
|
|
#include "effectmanager.h" |
29 |
|
|
#include "guild.h" |
30 |
|
|
#include "party.h" |
31 |
|
|
|
32 |
|
|
#include "being/localplayer.h" |
33 |
|
|
|
34 |
|
|
#include "particle/particleengine.h" |
35 |
|
|
|
36 |
|
|
#include "input/keyboardconfig.h" |
37 |
|
|
|
38 |
|
|
#include "gui/windows/outfitwindow.h" |
39 |
|
|
#include "gui/windows/socialwindow.h" |
40 |
|
|
|
41 |
|
|
#include "net/beinghandler.h" |
42 |
|
|
#include "net/serverfeatures.h" |
43 |
|
|
|
44 |
|
|
#include "net/messagein.h" |
45 |
|
|
|
46 |
|
|
#include "net/ea/beingrecv.h" |
47 |
|
|
|
48 |
|
|
#include "net/tmwa/guildmanager.h" |
49 |
|
|
#include "net/tmwa/sprite.h" |
50 |
|
|
|
51 |
|
|
#include "resources/iteminfo.h" |
52 |
|
|
|
53 |
|
|
#include "resources/db/itemdb.h" |
54 |
|
|
|
55 |
|
|
#include "utils/timer.h" |
56 |
|
|
|
57 |
|
|
#include "debug.h" |
58 |
|
|
|
59 |
|
|
extern Window *deathNotice; |
60 |
|
|
|
61 |
|
|
namespace TmwAthena |
62 |
|
|
{ |
63 |
|
|
|
64 |
|
|
static void setGm(Being *const dstBeing, |
65 |
|
|
const uint16_t gmstatus) |
66 |
|
|
{ |
67 |
|
|
if (dstBeing != localPlayer && |
68 |
|
|
gmstatus == 0x80) |
69 |
|
|
{ |
70 |
|
|
dstBeing->setGroupId(paths.getIntValue("gmDefaultLevel")); |
71 |
|
|
} |
72 |
|
|
else |
73 |
|
|
{ |
74 |
|
|
dstBeing->setGroupId(gmstatus); |
75 |
|
|
} |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
void BeingRecv::processBeingChangeLook(Net::MessageIn &msg) |
79 |
|
|
{ |
80 |
|
|
BLOCK_START("BeingRecv::processBeingChangeLook") |
81 |
|
|
if (actorManager == nullptr) |
82 |
|
|
{ |
83 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
84 |
|
|
return; |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
Being *const dstBeing = actorManager->findBeing( |
88 |
|
|
msg.readBeingId("being id")); |
89 |
|
|
|
90 |
|
|
const uint8_t type = msg.readUInt8("type"); |
91 |
|
|
const int16_t id = CAST_S16(msg.readUInt8("id")); |
92 |
|
|
const int id2 = 1; |
93 |
|
|
|
94 |
|
|
if ((localPlayer == nullptr) || (dstBeing == nullptr)) |
95 |
|
|
{ |
96 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
97 |
|
|
return; |
98 |
|
|
} |
99 |
|
|
processBeingChangeLookContinue(msg, dstBeing, type, id, id2); |
100 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
101 |
|
|
} |
102 |
|
|
|
103 |
|
|
void BeingRecv::processBeingChangeLook2(Net::MessageIn &msg) |
104 |
|
|
{ |
105 |
|
|
BLOCK_START("BeingRecv::processBeingChangeLook") |
106 |
|
|
if (actorManager == nullptr) |
107 |
|
|
{ |
108 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
109 |
|
|
return; |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
Being *const dstBeing = actorManager->findBeing( |
113 |
|
|
msg.readBeingId("being id")); |
114 |
|
|
|
115 |
|
|
const uint8_t type = msg.readUInt8("type"); |
116 |
|
|
int id2 = 0; |
117 |
|
|
|
118 |
|
|
const int16_t id = msg.readInt16("id1"); |
119 |
|
|
if (type == 2) |
120 |
|
|
{ |
121 |
|
|
id2 = msg.readInt16("id2"); |
122 |
|
|
} |
123 |
|
|
else |
124 |
|
|
{ |
125 |
|
|
msg.readInt16("id2"); |
126 |
|
|
id2 = 1; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
if ((localPlayer == nullptr) || (dstBeing == nullptr)) |
130 |
|
|
{ |
131 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
132 |
|
|
return; |
133 |
|
|
} |
134 |
|
|
processBeingChangeLookContinue(msg, dstBeing, type, id, id2); |
135 |
|
|
BLOCK_END("BeingRecv::processBeingChangeLook") |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
void BeingRecv::processBeingChangeLookContinue(const Net::MessageIn &msg, |
139 |
|
|
Being *const dstBeing, |
140 |
|
|
const uint8_t type, |
141 |
|
|
const int id, |
142 |
|
|
const int id2) |
143 |
|
|
{ |
144 |
|
|
if (dstBeing->getType() == ActorType::Player) |
145 |
|
|
dstBeing->setOtherTime(); |
146 |
|
|
|
147 |
|
|
switch (type) |
148 |
|
|
{ |
149 |
|
|
case 0: // change race |
150 |
|
|
dstBeing->setSubtype(fromInt(id, BeingTypeId), |
151 |
|
|
dstBeing->getLook()); |
152 |
|
|
break; |
153 |
|
|
case 1: // eAthena LOOK_HAIR |
154 |
|
|
{ |
155 |
|
|
const uint16_t look = CAST_U16(id / 256); |
156 |
|
|
const int hair = id % 256; |
157 |
|
|
dstBeing->setHairStyle(SPRITE_HAIR_COLOR, hair * -1); |
158 |
|
|
dstBeing->setLook(look); |
159 |
|
|
break; |
160 |
|
|
} |
161 |
|
|
case 2: // Weapon ID in id, Shield ID in id2 |
162 |
|
|
dstBeing->setSpriteId(SPRITE_BODY, |
163 |
|
|
id); |
164 |
|
|
dstBeing->setWeaponId(id); |
165 |
|
|
dstBeing->setSpriteId(SPRITE_FLOOR, |
166 |
|
|
id2); |
167 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR); |
168 |
|
|
break; |
169 |
|
|
case 3: // Change lower headgear for eAthena, pants for us |
170 |
|
|
dstBeing->setSpriteId(SPRITE_WEAPON, |
171 |
|
|
id); |
172 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_WEAPON); |
173 |
|
|
break; |
174 |
|
|
case 4: // Change upper headgear for eAthena, hat for us |
175 |
|
|
dstBeing->setSpriteId(SPRITE_CLOTHES_COLOR, |
176 |
|
|
id); |
177 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_CLOTHES_COLOR); |
178 |
|
|
break; |
179 |
|
|
case 5: // Change middle headgear for eathena, armor for us |
180 |
|
|
dstBeing->setSpriteId(SPRITE_HEAD_BOTTOM, |
181 |
|
|
id); |
182 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_BOTTOM); |
183 |
|
|
break; |
184 |
|
|
case 6: // eAthena LOOK_HAIR_COLOR |
185 |
|
|
dstBeing->setHairColor(SPRITE_HAIR_COLOR, |
186 |
|
|
fromInt(id, ItemColor)); |
187 |
|
|
break; |
188 |
|
|
case 7: // Clothes color |
189 |
|
|
// ignoring it |
190 |
|
|
break; |
191 |
|
|
case 8: // eAthena LOOK_SHIELD |
192 |
|
|
dstBeing->setSpriteId(SPRITE_FLOOR, |
193 |
|
|
id); |
194 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_FLOOR); |
195 |
|
|
break; |
196 |
|
|
case 9: // eAthena LOOK_SHOES |
197 |
|
|
dstBeing->setSpriteId(SPRITE_HAIR, |
198 |
|
|
id); |
199 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_HAIR); |
200 |
|
|
break; |
201 |
|
|
case 10: // LOOK_GLOVES |
202 |
|
|
dstBeing->setSpriteId(SPRITE_SHOES, |
203 |
|
|
id); |
204 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_SHOES); |
205 |
|
|
break; |
206 |
|
|
case 11: // LOOK_CAPE |
207 |
|
|
dstBeing->setSpriteId(SPRITE_SHIELD, |
208 |
|
|
id); |
209 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_SHIELD); |
210 |
|
|
break; |
211 |
|
|
case 12: |
212 |
|
|
dstBeing->setSpriteId(SPRITE_HEAD_TOP, |
213 |
|
|
id); |
214 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_TOP); |
215 |
|
|
break; |
216 |
|
|
case 13: |
217 |
|
|
dstBeing->setSpriteId(SPRITE_HEAD_MID, |
218 |
|
|
id); |
219 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_HEAD_MID); |
220 |
|
|
break; |
221 |
|
|
case 14: |
222 |
|
|
dstBeing->setSpriteId(SPRITE_ROBE, |
223 |
|
|
id); |
224 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_ROBE); |
225 |
|
|
break; |
226 |
|
|
case 15: |
227 |
|
|
dstBeing->setSpriteId(SPRITE_EVOL2, |
228 |
|
|
id); |
229 |
|
|
localPlayer->imitateOutfit(dstBeing, SPRITE_EVOL2); |
230 |
|
|
break; |
231 |
|
|
case 16: |
232 |
|
|
dstBeing->setLook(CAST_U16(id)); |
233 |
|
|
break; |
234 |
|
|
default: |
235 |
|
|
UNIMPLEMENTEDPACKETFIELD(type); |
236 |
|
|
break; |
237 |
|
|
} |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
void BeingRecv::processPlayerUpdate1(Net::MessageIn &msg) |
241 |
|
|
{ |
242 |
|
|
BLOCK_START("BeingRecv::processPlayerMoveUpdate") |
243 |
|
|
if ((actorManager == nullptr) || (localPlayer == nullptr)) |
244 |
|
|
{ |
245 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
246 |
|
|
return; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
// An update about a player, potentially including movement. |
250 |
|
|
const BeingId id = msg.readBeingId("account id"); |
251 |
|
|
const int16_t speed = msg.readInt16("speed"); |
252 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
253 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
254 |
|
|
const uint32_t option = msg.readInt16("option"); |
255 |
|
|
const int16_t job = msg.readInt16("job"); |
256 |
|
|
int disguiseId = 0; |
257 |
|
|
if (toInt(id, int) < 110000000 && job >= 1000) |
258 |
|
|
disguiseId = job; |
259 |
|
|
|
260 |
|
|
Being *dstBeing = actorManager->findBeing(id); |
261 |
|
|
if (dstBeing == nullptr) |
262 |
|
|
{ |
263 |
|
|
if (actorManager->isBlocked(id) == true) |
264 |
|
|
{ |
265 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
266 |
|
|
return; |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
dstBeing = Ea::BeingRecv::createBeing(id, job); |
270 |
|
|
|
271 |
|
|
if (dstBeing == nullptr) |
272 |
|
|
{ |
273 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
274 |
|
|
return; |
275 |
|
|
} |
276 |
|
|
} |
277 |
|
|
else if (disguiseId != 0) |
278 |
|
|
{ |
279 |
|
|
actorManager->undelete(dstBeing); |
280 |
|
|
beingHandler->requestNameById(id); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
uint8_t dir = dstBeing->getDirectionDelayed(); |
284 |
|
|
if (dir != 0U) |
285 |
|
|
{ |
286 |
|
|
if (dir != dstBeing->getDirection()) |
287 |
|
|
dstBeing->setDirection(dir); |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
if (Party *const party = localPlayer->getParty()) |
291 |
|
|
{ |
292 |
|
|
if (party->isMember(id)) |
293 |
|
|
dstBeing->setParty(party); |
294 |
|
|
} |
295 |
|
|
|
296 |
|
|
dstBeing->setWalkSpeed(speed); |
297 |
|
|
|
298 |
|
|
const uint8_t hairStyle = msg.readUInt8("hair style"); |
299 |
|
|
const uint16_t look = msg.readUInt8("look"); |
300 |
|
|
dstBeing->setSubtype(fromInt(job, BeingTypeId), look); |
301 |
|
|
const uint16_t weapon = msg.readInt16("weapon"); |
302 |
|
|
const uint16_t shield = msg.readInt16("shield"); |
303 |
|
|
const uint16_t headBottom = msg.readInt16("head bottom"); |
304 |
|
|
|
305 |
|
|
const uint16_t headTop = msg.readInt16("head top"); |
306 |
|
|
const uint16_t headMid = msg.readInt16("head mid"); |
307 |
|
|
const ItemColor hairColor = fromInt( |
308 |
|
|
msg.readUInt8("hair color"), ItemColor); |
309 |
|
|
msg.readUInt8("unused"); |
310 |
|
|
msg.readInt32("unused"); |
311 |
|
|
|
312 |
|
|
const int guild = msg.readInt32("guild"); |
313 |
|
|
|
314 |
|
|
if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot()) |
315 |
|
|
{ |
316 |
|
|
if (guild == 0) |
317 |
|
|
dstBeing->clearGuilds(); |
318 |
|
|
else |
319 |
|
|
dstBeing->setGuild(Guild::getGuild(CAST_S16(guild))); |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
msg.readInt16("emblem"); |
323 |
|
|
dstBeing->setManner(msg.readInt16("manner")); |
324 |
|
|
const uint32_t opt3 = msg.readInt16("opt3"); |
325 |
|
|
dstBeing->setKarma(msg.readUInt8("karma")); |
326 |
|
|
// reserving bit for future usage |
327 |
|
|
dstBeing->setGender(Being::intToGender( |
328 |
|
|
CAST_U8(msg.readUInt8("gender") & 3))); |
329 |
|
|
|
330 |
|
|
if (disguiseId == 0) |
331 |
|
|
{ |
332 |
|
|
// Set these after the gender, as the sprites may be gender-specific |
333 |
|
|
dstBeing->updateSprite(SPRITE_BODY, |
334 |
|
|
weapon, |
335 |
|
|
std::string()); |
336 |
|
|
dstBeing->setWeaponId(weapon); |
337 |
|
|
dstBeing->updateSprite(SPRITE_FLOOR, shield, std::string()); |
338 |
|
|
dstBeing->updateSprite(SPRITE_WEAPON, headBottom, std::string()); |
339 |
|
|
dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid, std::string()); |
340 |
|
|
dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop, std::string()); |
341 |
|
|
if (hairStyle == 0) |
342 |
|
|
{ |
343 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
344 |
|
|
0, |
345 |
|
|
std::string()); |
346 |
|
|
} |
347 |
|
|
else |
348 |
|
|
{ |
349 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
350 |
|
|
hairStyle * -1, |
351 |
|
|
ItemDB::get(-hairStyle).getDyeColorsString(hairColor)); |
352 |
|
|
} |
353 |
|
|
dstBeing->setHairColor(hairColor); |
354 |
|
|
} |
355 |
|
|
localPlayer->imitateOutfit(dstBeing, -1); |
356 |
|
|
|
357 |
|
|
uint16_t x; |
358 |
|
|
uint16_t y; |
359 |
|
|
msg.readCoordinates(x, y, dir, "position"); |
360 |
|
|
dstBeing->setTileCoords(x, y); |
361 |
|
|
dstBeing->setDirection(dir); |
362 |
|
|
|
363 |
|
|
localPlayer->imitateDirection(dstBeing, dir); |
364 |
|
|
|
365 |
|
|
const uint16_t gmstatus = msg.readInt16("gm status"); |
366 |
|
|
|
367 |
|
|
setGm(dstBeing, gmstatus); |
368 |
|
|
|
369 |
|
|
applyPlayerAction(msg, dstBeing, msg.readUInt8("action type")); |
370 |
|
|
const int level = CAST_S32(msg.readUInt8("level")); |
371 |
|
|
if (level != 0) |
372 |
|
|
dstBeing->setLevel(level); |
373 |
|
|
|
374 |
|
|
msg.readUInt8("unused"); |
375 |
|
|
|
376 |
|
|
dstBeing->setActionTime(tick_time); |
377 |
|
|
|
378 |
|
|
dstBeing->setStatusEffectOpitons(option, |
379 |
|
|
opt1, |
380 |
|
|
opt2, |
381 |
|
|
opt3); |
382 |
|
|
|
383 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
void BeingRecv::processPlayerUpdate2(Net::MessageIn &msg) |
387 |
|
|
{ |
388 |
|
|
BLOCK_START("BeingRecv::processPlayerMoveUpdate") |
389 |
|
|
if ((actorManager == nullptr) || (localPlayer == nullptr)) |
390 |
|
|
{ |
391 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
392 |
|
|
return; |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
// An update about a player, potentially including movement. |
396 |
|
|
const BeingId id = msg.readBeingId("account id"); |
397 |
|
|
const int16_t speed = msg.readInt16("speed"); |
398 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
399 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
400 |
|
|
const uint32_t option = msg.readInt16("option"); |
401 |
|
|
const int16_t job = msg.readInt16("job"); |
402 |
|
|
int disguiseId = 0; |
403 |
|
|
if (toInt(id, int) < 110000000 && job >= 1000) |
404 |
|
|
disguiseId = job; |
405 |
|
|
|
406 |
|
|
Being *dstBeing = actorManager->findBeing(id); |
407 |
|
|
if (dstBeing == nullptr) |
408 |
|
|
{ |
409 |
|
|
if (actorManager->isBlocked(id) == true) |
410 |
|
|
{ |
411 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
412 |
|
|
return; |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
dstBeing = Ea::BeingRecv::createBeing(id, job); |
416 |
|
|
|
417 |
|
|
if (dstBeing == nullptr) |
418 |
|
|
{ |
419 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
420 |
|
|
return; |
421 |
|
|
} |
422 |
|
|
} |
423 |
|
|
else if (disguiseId != 0) |
424 |
|
|
{ |
425 |
|
|
actorManager->undelete(dstBeing); |
426 |
|
|
beingHandler->requestNameById(id); |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
uint8_t dir = dstBeing->getDirectionDelayed(); |
430 |
|
|
if (dir != 0U) |
431 |
|
|
{ |
432 |
|
|
if (dir != dstBeing->getDirection()) |
433 |
|
|
dstBeing->setDirection(dir); |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
if (Party *const party = localPlayer->getParty()) |
437 |
|
|
{ |
438 |
|
|
if (party->isMember(id)) |
439 |
|
|
dstBeing->setParty(party); |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
dstBeing->setWalkSpeed(speed); |
443 |
|
|
|
444 |
|
|
const uint8_t hairStyle = msg.readUInt8("hair style"); |
445 |
|
|
const uint16_t look = msg.readUInt8("look"); |
446 |
|
|
dstBeing->setSubtype(fromInt(job, BeingTypeId), look); |
447 |
|
|
const uint16_t weapon = msg.readInt16("weapon"); |
448 |
|
|
const uint16_t shield = msg.readInt16("shield"); |
449 |
|
|
const uint16_t headBottom = msg.readInt16("head bottom"); |
450 |
|
|
const uint16_t headTop = msg.readInt16("head top"); |
451 |
|
|
const uint16_t headMid = msg.readInt16("head mid"); |
452 |
|
|
const ItemColor hairColor = fromInt( |
453 |
|
|
msg.readUInt8("hair color"), ItemColor); |
454 |
|
|
msg.readUInt8("unused"); |
455 |
|
|
msg.readInt32("unused"); |
456 |
|
|
|
457 |
|
|
const int guild = msg.readInt32("guild"); |
458 |
|
|
|
459 |
|
|
if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot()) |
460 |
|
|
{ |
461 |
|
|
if (guild == 0) |
462 |
|
|
dstBeing->clearGuilds(); |
463 |
|
|
else |
464 |
|
|
dstBeing->setGuild(Guild::getGuild(CAST_S16(guild))); |
465 |
|
|
} |
466 |
|
|
|
467 |
|
|
msg.readInt16("emblem"); |
468 |
|
|
dstBeing->setManner(msg.readInt16("manner")); |
469 |
|
|
const uint32_t opt3 = msg.readInt16("opt3"); |
470 |
|
|
dstBeing->setKarma(msg.readUInt8("karma")); |
471 |
|
|
// reserving bit for future usage |
472 |
|
|
dstBeing->setGender(Being::intToGender( |
473 |
|
|
CAST_U8(msg.readUInt8("gender") & 3))); |
474 |
|
|
|
475 |
|
|
if (disguiseId == 0) |
476 |
|
|
{ |
477 |
|
|
// Set these after the gender, as the sprites may be gender-specific |
478 |
|
|
dstBeing->updateSprite(SPRITE_BODY, |
479 |
|
|
weapon, |
480 |
|
|
std::string()); |
481 |
|
|
dstBeing->setWeaponId(weapon); |
482 |
|
|
dstBeing->updateSprite(SPRITE_FLOOR, shield, std::string()); |
483 |
|
|
dstBeing->updateSprite(SPRITE_WEAPON, headBottom, std::string()); |
484 |
|
|
dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid, std::string()); |
485 |
|
|
dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop, std::string()); |
486 |
|
|
if (hairStyle == 0) |
487 |
|
|
{ |
488 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
489 |
|
|
0, |
490 |
|
|
std::string()); |
491 |
|
|
} |
492 |
|
|
else |
493 |
|
|
{ |
494 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
495 |
|
|
hairStyle * -1, |
496 |
|
|
ItemDB::get(-hairStyle).getDyeColorsString(hairColor)); |
497 |
|
|
} |
498 |
|
|
dstBeing->setHairColor(hairColor); |
499 |
|
|
} |
500 |
|
|
localPlayer->imitateOutfit(dstBeing, -1); |
501 |
|
|
|
502 |
|
|
uint16_t x; |
503 |
|
|
uint16_t y; |
504 |
|
|
msg.readCoordinates(x, y, dir, "position"); |
505 |
|
|
dstBeing->setTileCoords(x, y); |
506 |
|
|
dstBeing->setDirection(dir); |
507 |
|
|
|
508 |
|
|
localPlayer->imitateDirection(dstBeing, dir); |
509 |
|
|
|
510 |
|
|
const uint16_t gmstatus = msg.readInt16("gm status"); |
511 |
|
|
|
512 |
|
|
setGm(dstBeing, gmstatus); |
513 |
|
|
|
514 |
|
|
applyPlayerAction(msg, dstBeing, msg.readUInt8("action type")); |
515 |
|
|
const int level = CAST_S32(msg.readUInt8("level")); |
516 |
|
|
if (level != 0) |
517 |
|
|
dstBeing->setLevel(level); |
518 |
|
|
|
519 |
|
|
dstBeing->setActionTime(tick_time); |
520 |
|
|
dstBeing->setStatusEffectOpitons(option, |
521 |
|
|
opt1, |
522 |
|
|
opt2, |
523 |
|
|
opt3); |
524 |
|
|
|
525 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
void BeingRecv::processPlayerMove(Net::MessageIn &msg) |
529 |
|
|
{ |
530 |
|
|
BLOCK_START("BeingRecv::processPlayerMoveUpdate") |
531 |
|
|
if ((actorManager == nullptr) || (localPlayer == nullptr)) |
532 |
|
|
{ |
533 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
534 |
|
|
return; |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
// An update about a player, potentially including movement. |
538 |
|
|
const BeingId id = msg.readBeingId("account id"); |
539 |
|
|
const int16_t speed = msg.readInt16("speed"); |
540 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
541 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
542 |
|
|
const uint32_t option = msg.readInt16("option"); |
543 |
|
|
const int16_t job = msg.readInt16("job"); |
544 |
|
|
int disguiseId = 0; |
545 |
|
|
if (toInt(id, int) < 110000000 && job >= 1000) |
546 |
|
|
disguiseId = job; |
547 |
|
|
|
548 |
|
|
Being *dstBeing = actorManager->findBeing(id); |
549 |
|
|
if (dstBeing == nullptr) |
550 |
|
|
{ |
551 |
|
|
if (actorManager->isBlocked(id) == true) |
552 |
|
|
{ |
553 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
554 |
|
|
return; |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
dstBeing = Ea::BeingRecv::createBeing(id, job); |
558 |
|
|
|
559 |
|
|
if (dstBeing == nullptr) |
560 |
|
|
{ |
561 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
562 |
|
|
return; |
563 |
|
|
} |
564 |
|
|
} |
565 |
|
|
else if (disguiseId != 0) |
566 |
|
|
{ |
567 |
|
|
actorManager->undelete(dstBeing); |
568 |
|
|
beingHandler->requestNameById(id); |
569 |
|
|
} |
570 |
|
|
|
571 |
|
|
const uint8_t dir = dstBeing->getDirectionDelayed(); |
572 |
|
|
if (dir != 0U) |
573 |
|
|
{ |
574 |
|
|
if (dir != dstBeing->getDirection()) |
575 |
|
|
dstBeing->setDirection(dir); |
576 |
|
|
} |
577 |
|
|
|
578 |
|
|
if (Party *const party = localPlayer->getParty()) |
579 |
|
|
{ |
580 |
|
|
if (party->isMember(id)) |
581 |
|
|
dstBeing->setParty(party); |
582 |
|
|
} |
583 |
|
|
|
584 |
|
|
dstBeing->setWalkSpeed(speed); |
585 |
|
|
|
586 |
|
|
const uint8_t hairStyle = msg.readUInt8("hair style"); |
587 |
|
|
const uint16_t look = msg.readUInt8("look"); |
588 |
|
|
dstBeing->setSubtype(fromInt(job, BeingTypeId), look); |
589 |
|
|
const uint16_t weapon = msg.readInt16("weapon"); |
590 |
|
|
const uint16_t shield = msg.readInt16("shield"); |
591 |
|
|
const uint16_t headBottom = msg.readInt16("head bottom"); |
592 |
|
|
|
593 |
|
|
msg.readInt32("tick"); |
594 |
|
|
|
595 |
|
|
const uint16_t headTop = msg.readInt16("head top"); |
596 |
|
|
const uint16_t headMid = msg.readInt16("head mid"); |
597 |
|
|
const ItemColor hairColor = fromInt( |
598 |
|
|
msg.readUInt8("hair color"), ItemColor); |
599 |
|
|
msg.readUInt8("unused"); |
600 |
|
|
msg.readInt32("unused"); |
601 |
|
|
|
602 |
|
|
const int guild = msg.readInt32("guild"); |
603 |
|
|
|
604 |
|
|
if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot()) |
605 |
|
|
{ |
606 |
|
|
if (guild == 0) |
607 |
|
|
dstBeing->clearGuilds(); |
608 |
|
|
else |
609 |
|
|
dstBeing->setGuild(Guild::getGuild(CAST_S16(guild))); |
610 |
|
|
} |
611 |
|
|
|
612 |
|
|
msg.readInt16("emblem"); |
613 |
|
|
dstBeing->setManner(msg.readInt16("manner")); |
614 |
|
|
const uint32_t opt3 = msg.readInt16("opt3"); |
615 |
|
|
dstBeing->setKarma(msg.readUInt8("karma")); |
616 |
|
|
// reserving bit for future usage |
617 |
|
|
dstBeing->setGender(Being::intToGender( |
618 |
|
|
CAST_U8(msg.readUInt8("gender") & 3))); |
619 |
|
|
|
620 |
|
|
if (disguiseId == 0) |
621 |
|
|
{ |
622 |
|
|
// Set these after the gender, as the sprites may be gender-specific |
623 |
|
|
dstBeing->updateSprite(SPRITE_BODY, |
624 |
|
|
weapon, |
625 |
|
|
std::string()); |
626 |
|
|
dstBeing->setWeaponId(weapon); |
627 |
|
|
dstBeing->updateSprite(SPRITE_FLOOR, shield, std::string()); |
628 |
|
|
dstBeing->updateSprite(SPRITE_WEAPON, headBottom, std::string()); |
629 |
|
|
dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid, std::string()); |
630 |
|
|
dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop, std::string()); |
631 |
|
|
if (hairStyle == 0) |
632 |
|
|
{ |
633 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
634 |
|
|
0, |
635 |
|
|
std::string()); |
636 |
|
|
} |
637 |
|
|
else |
638 |
|
|
{ |
639 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
640 |
|
|
hairStyle * -1, |
641 |
|
|
ItemDB::get(-hairStyle).getDyeColorsString(hairColor)); |
642 |
|
|
} |
643 |
|
|
dstBeing->setHairColor(hairColor); |
644 |
|
|
} |
645 |
|
|
localPlayer->imitateOutfit(dstBeing, -1); |
646 |
|
|
|
647 |
|
|
uint16_t srcX; |
648 |
|
|
uint16_t srcY; |
649 |
|
|
uint16_t dstX; |
650 |
|
|
uint16_t dstY; |
651 |
|
|
msg.readCoordinatePair(srcX, srcY, dstX, dstY, "moving path"); |
652 |
|
|
|
653 |
|
|
localPlayer->followMoveTo(dstBeing, srcX, srcY, dstX, dstY); |
654 |
|
|
|
655 |
|
|
dstBeing->setTileCoords(srcX, srcY); |
656 |
|
|
dstBeing->setDestination(dstX, dstY); |
657 |
|
|
|
658 |
|
|
// because server don't send direction in move packet, |
659 |
|
|
// we fixing it |
660 |
|
|
|
661 |
|
|
if (srcX != dstX || srcY != dstY) |
662 |
|
|
{ |
663 |
|
|
const int d = dstBeing->calcDirection(dstX, dstY); |
664 |
|
|
|
665 |
|
|
if ((d != 0) && dstBeing->getDirection() != d) |
666 |
|
|
dstBeing->setDirectionDelayed(CAST_U8(d)); |
667 |
|
|
} |
668 |
|
|
|
669 |
|
|
if (localPlayer->getCurrentAction() != BeingAction::STAND) |
670 |
|
|
localPlayer->imitateAction(dstBeing, BeingAction::STAND); |
671 |
|
|
if (localPlayer->getDirection() != dstBeing->getDirection()) |
672 |
|
|
{ |
673 |
|
|
localPlayer->imitateDirection(dstBeing, |
674 |
|
|
dstBeing->getDirection()); |
675 |
|
|
} |
676 |
|
|
|
677 |
|
|
const uint16_t gmstatus = msg.readInt16("gm status"); |
678 |
|
|
|
679 |
|
|
setGm(dstBeing, gmstatus); |
680 |
|
|
|
681 |
|
|
msg.readUInt8("unused"); |
682 |
|
|
|
683 |
|
|
const int level = CAST_S32(msg.readUInt8("level")); |
684 |
|
|
if (level != 0) |
685 |
|
|
dstBeing->setLevel(level); |
686 |
|
|
|
687 |
|
|
msg.readUInt8("unused"); |
688 |
|
|
|
689 |
|
|
if (dstBeing->getType() != ActorType::Player) |
690 |
|
|
dstBeing->setActionTime(tick_time); |
691 |
|
|
|
692 |
|
|
dstBeing->setStatusEffectOpitons(option, |
693 |
|
|
opt1, |
694 |
|
|
opt2, |
695 |
|
|
opt3); |
696 |
|
|
|
697 |
|
|
if (dstBeing->getType() == ActorType::Player) |
698 |
|
|
dstBeing->setMoveTime(); |
699 |
|
|
BLOCK_END("BeingRecv::processPlayerMoveUpdate") |
700 |
|
|
} |
701 |
|
|
|
702 |
|
|
void BeingRecv::processBeingVisible(Net::MessageIn &msg) |
703 |
|
|
{ |
704 |
|
|
BLOCK_START("BeingRecv::processBeingVisibleOrMove") |
705 |
|
|
if (actorManager == nullptr) |
706 |
|
|
{ |
707 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
708 |
|
|
return; |
709 |
|
|
} |
710 |
|
|
|
711 |
|
|
BeingId spawnId; |
712 |
|
|
|
713 |
|
|
// Information about a being in range |
714 |
|
|
const BeingId id = msg.readBeingId("being id"); |
715 |
|
|
if (id == Ea::BeingRecv::mSpawnId) |
716 |
|
|
spawnId = Ea::BeingRecv::mSpawnId; |
717 |
|
|
else |
718 |
|
|
spawnId = BeingId_zero; |
719 |
|
|
Ea::BeingRecv::mSpawnId = BeingId_zero; |
720 |
|
|
int16_t speed = msg.readInt16("speed"); |
721 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
722 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
723 |
|
|
const uint32_t option = msg.readInt16("option"); |
724 |
|
|
const int16_t job = msg.readInt16("class"); |
725 |
|
|
int disguiseId = 0; |
726 |
|
|
if (id == localPlayer->getId() && job >= 1000) |
727 |
|
|
disguiseId = job; |
728 |
|
|
|
729 |
|
|
Being *dstBeing = actorManager->findBeing(id); |
730 |
|
|
|
731 |
|
|
if ((dstBeing != nullptr) && dstBeing->getType() == ActorType::Monster |
732 |
|
|
&& !dstBeing->isAlive()) |
733 |
|
|
{ |
734 |
|
|
actorManager->destroy(dstBeing); |
735 |
|
|
actorManager->erase(dstBeing); |
736 |
|
|
dstBeing = nullptr; |
737 |
|
|
} |
738 |
|
|
|
739 |
|
|
if (dstBeing == nullptr) |
740 |
|
|
{ |
741 |
|
|
// Being with id >= 110000000 and job 0 are better |
742 |
|
|
// known as ghosts, so don't create those. |
743 |
|
|
if (job == 0 && toInt(id, int) >= 110000000) |
744 |
|
|
{ |
745 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
746 |
|
|
return; |
747 |
|
|
} |
748 |
|
|
|
749 |
|
|
if (actorManager->isBlocked(id) == true) |
750 |
|
|
{ |
751 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
752 |
|
|
return; |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
dstBeing = Ea::BeingRecv::createBeing(id, job); |
756 |
|
|
|
757 |
|
|
if (dstBeing == nullptr) |
758 |
|
|
{ |
759 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
760 |
|
|
return; |
761 |
|
|
} |
762 |
|
|
} |
763 |
|
|
else |
764 |
|
|
{ |
765 |
|
|
if (dstBeing->getType() == ActorType::Npc) |
766 |
|
|
{ |
767 |
|
|
actorManager->undelete(dstBeing); |
768 |
|
|
beingHandler->requestNameById(id); |
769 |
|
|
} |
770 |
|
|
} |
771 |
|
|
|
772 |
|
|
if (dstBeing->getType() == ActorType::Player) |
773 |
|
|
dstBeing->setMoveTime(); |
774 |
|
|
|
775 |
|
|
if (spawnId != BeingId_zero) |
776 |
|
|
{ |
777 |
|
|
dstBeing->setAction(BeingAction::SPAWN, 0); |
778 |
|
|
} |
779 |
|
|
else |
780 |
|
|
{ |
781 |
|
|
dstBeing->clearPath(); |
782 |
|
|
dstBeing->setActionTime(tick_time); |
783 |
|
|
dstBeing->setAction(BeingAction::STAND, 0); |
784 |
|
|
} |
785 |
|
|
|
786 |
|
|
// Prevent division by 0 when calculating frame |
787 |
|
|
if (speed == 0) |
788 |
|
|
speed = 150; |
789 |
|
|
|
790 |
|
|
const uint8_t hairStyle = msg.readUInt8("hair style"); |
791 |
|
|
const uint16_t look = msg.readUInt8("look"); |
792 |
|
|
dstBeing->setSubtype(fromInt(job, BeingTypeId), look); |
793 |
|
|
if (dstBeing->getType() == ActorType::Monster && (localPlayer != nullptr)) |
794 |
|
|
localPlayer->checkNewName(dstBeing); |
795 |
|
|
dstBeing->setWalkSpeed(speed); |
796 |
|
|
const uint16_t weapon = msg.readInt16("weapon"); |
797 |
|
|
const uint16_t headBottom = msg.readInt16("head bottom"); |
798 |
|
|
|
799 |
|
|
const uint16_t shield = msg.readInt16("shield"); |
800 |
|
|
const uint16_t headTop = msg.readInt16("head top"); |
801 |
|
|
const uint16_t headMid = msg.readInt16("head mid"); |
802 |
|
|
const ItemColor hairColor = fromInt(msg.readUInt8("hair color"), |
803 |
|
|
ItemColor); |
804 |
|
|
msg.readUInt8("unused"); |
805 |
|
|
const uint16_t shoes = msg.readInt16("shoes / clothes color"); |
806 |
|
|
|
807 |
|
|
uint16_t gloves; |
808 |
|
|
if (dstBeing->getType() == ActorType::Monster) |
809 |
|
|
{ |
810 |
|
|
if (serverFeatures->haveServerHp()) |
811 |
|
|
{ |
812 |
|
|
const int hp = msg.readInt32("hp"); |
813 |
|
|
const int maxHP = msg.readInt32("max hp"); |
814 |
|
|
if ((hp != 0) && (maxHP != 0)) |
815 |
|
|
{ |
816 |
|
|
dstBeing->setMaxHP(maxHP); |
817 |
|
|
const int oldHP = dstBeing->getHP(); |
818 |
|
|
if ((oldHP == 0) || oldHP > hp) |
819 |
|
|
dstBeing->setHP(hp); |
820 |
|
|
} |
821 |
|
|
} |
822 |
|
|
else |
823 |
|
|
{ |
824 |
|
|
msg.readInt32("unused"); |
825 |
|
|
msg.readInt32("unused"); |
826 |
|
|
} |
827 |
|
|
gloves = 0; |
828 |
|
|
} |
829 |
|
|
else |
830 |
|
|
{ |
831 |
|
|
gloves = msg.readInt16("gloves / head dir"); |
832 |
|
|
msg.readInt32("guild"); |
833 |
|
|
msg.readInt16("guild emblem"); |
834 |
|
|
} |
835 |
|
|
|
836 |
|
|
dstBeing->setManner(msg.readInt16("manner")); |
837 |
|
|
const uint32_t opt3 = msg.readInt16("opt3"); |
838 |
|
|
if (serverFeatures->haveMonsterAttackRange() |
839 |
|
|
&& dstBeing->getType() == ActorType::Monster) |
840 |
|
|
{ |
841 |
|
|
const int attackRange = CAST_S32( |
842 |
|
|
msg.readUInt8("attack range (was karma)")); |
843 |
|
|
dstBeing->setAttackRange(attackRange); |
844 |
|
|
} |
845 |
|
|
else |
846 |
|
|
{ |
847 |
|
|
dstBeing->setKarma(msg.readUInt8("karma")); |
848 |
|
|
} |
849 |
|
|
uint8_t gender = msg.readUInt8("gender"); |
850 |
|
|
|
851 |
|
|
if ((disguiseId == 0) && dstBeing->getType() == ActorType::Player) |
852 |
|
|
{ |
853 |
|
|
// reserving bits for future usage |
854 |
|
|
gender &= 3; |
855 |
|
|
dstBeing->setGender(Being::intToGender(gender)); |
856 |
|
|
// Set these after the gender, as the sprites may be gender-specific |
857 |
|
|
if (hairStyle == 0) |
858 |
|
|
{ |
859 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, 0, std::string()); |
860 |
|
|
} |
861 |
|
|
else |
862 |
|
|
{ |
863 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
864 |
|
|
hairStyle * -1, |
865 |
|
|
ItemDB::get(-hairStyle).getDyeColorsString(hairColor)); |
866 |
|
|
} |
867 |
|
|
dstBeing->setHairColor(hairColor); |
868 |
|
|
dstBeing->updateSprite(SPRITE_WEAPON, headBottom, std::string()); |
869 |
|
|
dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid, std::string()); |
870 |
|
|
dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop, std::string()); |
871 |
|
|
dstBeing->updateSprite(SPRITE_HAIR, shoes, std::string()); |
872 |
|
|
dstBeing->updateSprite(SPRITE_SHOES, gloves, std::string()); |
873 |
|
|
dstBeing->updateSprite(SPRITE_BODY, weapon, std::string()); |
874 |
|
|
dstBeing->setWeaponId(weapon); |
875 |
|
|
dstBeing->updateSprite(SPRITE_FLOOR, shield, std::string()); |
876 |
|
|
} |
877 |
|
|
else if (dstBeing->getType() == ActorType::Npc |
878 |
|
|
&& serverFeatures->haveNpcGender()) |
879 |
|
|
{ |
880 |
|
|
setServerGender(dstBeing, gender); |
881 |
|
|
} |
882 |
|
|
|
883 |
|
|
uint8_t dir; |
884 |
|
|
uint16_t x; |
885 |
|
|
uint16_t y; |
886 |
|
|
msg.readCoordinates(x, y, dir, "position"); |
887 |
|
|
dstBeing->setTileCoords(x, y); |
888 |
|
|
|
889 |
|
|
if (job == 45 && (socialWindow != nullptr) && (outfitWindow != nullptr)) |
890 |
|
|
{ |
891 |
|
|
const int num = socialWindow->getPortalIndex(x, y); |
892 |
|
|
if (num >= 0) |
893 |
|
|
{ |
894 |
|
|
dstBeing->setName(KeyboardConfig::getKeyShortString( |
895 |
|
|
OutfitWindow::keyName(num))); |
896 |
|
|
} |
897 |
|
|
else |
898 |
|
|
{ |
899 |
|
|
dstBeing->setName(""); |
900 |
|
|
} |
901 |
|
|
} |
902 |
|
|
|
903 |
|
|
dstBeing->setDirection(dir); |
904 |
|
|
|
905 |
|
|
msg.readUInt8("unknown"); |
906 |
|
|
msg.readUInt8("unknown"); |
907 |
|
|
msg.readUInt8("unknown"); |
908 |
|
|
msg.readUInt8("unknown"); |
909 |
|
|
msg.readUInt8("unknown"); |
910 |
|
|
|
911 |
|
|
dstBeing->setStatusEffectOpitons(option, |
912 |
|
|
opt1, |
913 |
|
|
opt2, |
914 |
|
|
opt3); |
915 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
916 |
|
|
} |
917 |
|
|
|
918 |
|
|
void BeingRecv::processBeingMove(Net::MessageIn &msg) |
919 |
|
|
{ |
920 |
|
|
BLOCK_START("BeingRecv::processBeingVisibleOrMove") |
921 |
|
|
if (actorManager == nullptr) |
922 |
|
|
{ |
923 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
924 |
|
|
return; |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
BeingId spawnId; |
928 |
|
|
|
929 |
|
|
// Information about a being in range |
930 |
|
|
const BeingId id = msg.readBeingId("being id"); |
931 |
|
|
if (id == Ea::BeingRecv::mSpawnId) |
932 |
|
|
spawnId = Ea::BeingRecv::mSpawnId; |
933 |
|
|
else |
934 |
|
|
spawnId = BeingId_zero; |
935 |
|
|
Ea::BeingRecv::mSpawnId = BeingId_zero; |
936 |
|
|
int16_t speed = msg.readInt16("speed"); |
937 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
938 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
939 |
|
|
const uint32_t option = msg.readInt16("option"); |
940 |
|
|
const int16_t job = msg.readInt16("class"); |
941 |
|
|
int disguiseId = 0; |
942 |
|
|
if (id == localPlayer->getId() && job >= 1000) |
943 |
|
|
disguiseId = job; |
944 |
|
|
|
945 |
|
|
Being *dstBeing = actorManager->findBeing(id); |
946 |
|
|
|
947 |
|
|
if ((dstBeing != nullptr) && dstBeing->getType() == ActorType::Monster |
948 |
|
|
&& !dstBeing->isAlive()) |
949 |
|
|
{ |
950 |
|
|
actorManager->destroy(dstBeing); |
951 |
|
|
actorManager->erase(dstBeing); |
952 |
|
|
dstBeing = nullptr; |
953 |
|
|
} |
954 |
|
|
|
955 |
|
|
if (dstBeing == nullptr) |
956 |
|
|
{ |
957 |
|
|
// Being with id >= 110000000 and job 0 are better |
958 |
|
|
// known as ghosts, so don't create those. |
959 |
|
|
if (job == 0 && toInt(id, int) >= 110000000) |
960 |
|
|
{ |
961 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
962 |
|
|
return; |
963 |
|
|
} |
964 |
|
|
|
965 |
|
|
if (actorManager->isBlocked(id) == true) |
966 |
|
|
{ |
967 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
968 |
|
|
return; |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
dstBeing = Ea::BeingRecv::createBeing(id, job); |
972 |
|
|
|
973 |
|
|
if (dstBeing == nullptr) |
974 |
|
|
{ |
975 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
976 |
|
|
return; |
977 |
|
|
} |
978 |
|
|
} |
979 |
|
|
else |
980 |
|
|
{ |
981 |
|
|
if (dstBeing->getType() == ActorType::Npc) |
982 |
|
|
{ |
983 |
|
|
actorManager->undelete(dstBeing); |
984 |
|
|
beingHandler->requestNameById(id); |
985 |
|
|
} |
986 |
|
|
} |
987 |
|
|
|
988 |
|
|
if (dstBeing->getType() == ActorType::Player) |
989 |
|
|
dstBeing->setMoveTime(); |
990 |
|
|
|
991 |
|
|
if (spawnId != BeingId_zero) |
992 |
|
|
dstBeing->setAction(BeingAction::SPAWN, 0); |
993 |
|
|
|
994 |
|
|
// Prevent division by 0 when calculating frame |
995 |
|
|
if (speed == 0) |
996 |
|
|
speed = 150; |
997 |
|
|
|
998 |
|
|
const uint8_t hairStyle = msg.readUInt8("hair style"); |
999 |
|
|
const uint16_t look = msg.readUInt8("look"); |
1000 |
|
|
dstBeing->setSubtype(fromInt(job, BeingTypeId), look); |
1001 |
|
|
if (dstBeing->getType() == ActorType::Monster && (localPlayer != nullptr)) |
1002 |
|
|
localPlayer->checkNewName(dstBeing); |
1003 |
|
|
dstBeing->setWalkSpeed(speed); |
1004 |
|
|
const uint16_t weapon = msg.readInt16("weapon"); |
1005 |
|
|
const uint16_t headBottom = msg.readInt16("head bottom"); |
1006 |
|
|
|
1007 |
|
|
msg.readInt32("tick"); |
1008 |
|
|
|
1009 |
|
|
const uint16_t shield = msg.readInt16("shield"); |
1010 |
|
|
const uint16_t headTop = msg.readInt16("head top"); |
1011 |
|
|
const uint16_t headMid = msg.readInt16("head mid"); |
1012 |
|
|
const ItemColor hairColor = fromInt( |
1013 |
|
|
msg.readUInt8("hair color"), ItemColor); |
1014 |
|
|
msg.readUInt8("unused"); |
1015 |
|
|
const uint16_t shoes = msg.readInt16("shoes / clothes color"); |
1016 |
|
|
|
1017 |
|
|
uint16_t gloves; |
1018 |
|
|
if (dstBeing->getType() == ActorType::Monster) |
1019 |
|
|
{ |
1020 |
|
|
if (serverFeatures->haveServerHp()) |
1021 |
|
|
{ |
1022 |
|
|
const int hp = msg.readInt32("hp"); |
1023 |
|
|
const int maxHP = msg.readInt32("max hp"); |
1024 |
|
|
if ((hp != 0) && (maxHP != 0)) |
1025 |
|
|
{ |
1026 |
|
|
dstBeing->setMaxHP(maxHP); |
1027 |
|
|
const int oldHP = dstBeing->getHP(); |
1028 |
|
|
if ((oldHP == 0) || oldHP > hp) |
1029 |
|
|
dstBeing->setHP(hp); |
1030 |
|
|
} |
1031 |
|
|
} |
1032 |
|
|
else |
1033 |
|
|
{ |
1034 |
|
|
msg.readInt32("unused"); |
1035 |
|
|
msg.readInt32("unused"); |
1036 |
|
|
} |
1037 |
|
|
gloves = 0; |
1038 |
|
|
} |
1039 |
|
|
else |
1040 |
|
|
{ |
1041 |
|
|
gloves = msg.readInt16("gloves / head dir"); |
1042 |
|
|
msg.readInt32("guild"); |
1043 |
|
|
msg.readInt16("guild emblem"); |
1044 |
|
|
} |
1045 |
|
|
|
1046 |
|
|
dstBeing->setManner(msg.readInt16("manner")); |
1047 |
|
|
const uint32_t opt3 = msg.readInt16("opt3"); |
1048 |
|
|
if (serverFeatures->haveMonsterAttackRange() |
1049 |
|
|
&& dstBeing->getType() == ActorType::Monster) |
1050 |
|
|
{ |
1051 |
|
|
const int attackRange = CAST_S32( |
1052 |
|
|
msg.readUInt8("attack range (was karma)")); |
1053 |
|
|
dstBeing->setAttackRange(attackRange); |
1054 |
|
|
} |
1055 |
|
|
else |
1056 |
|
|
{ |
1057 |
|
|
dstBeing->setKarma(msg.readUInt8("karma")); |
1058 |
|
|
} |
1059 |
|
|
uint8_t gender = msg.readUInt8("gender"); |
1060 |
|
|
|
1061 |
|
|
if ((disguiseId == 0) && dstBeing->getType() == ActorType::Player) |
1062 |
|
|
{ |
1063 |
|
|
// reserving bits for future usage |
1064 |
|
|
gender &= 3; |
1065 |
|
|
dstBeing->setGender(Being::intToGender(gender)); |
1066 |
|
|
// Set these after the gender, as the sprites may be gender-specific |
1067 |
|
|
if (hairStyle == 0) |
1068 |
|
|
{ |
1069 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, 0, std::string()); |
1070 |
|
|
} |
1071 |
|
|
else |
1072 |
|
|
{ |
1073 |
|
|
dstBeing->updateSprite(SPRITE_HAIR_COLOR, |
1074 |
|
|
hairStyle * -1, |
1075 |
|
|
ItemDB::get(-hairStyle).getDyeColorsString(hairColor)); |
1076 |
|
|
} |
1077 |
|
|
dstBeing->setHairColor(hairColor); |
1078 |
|
|
dstBeing->updateSprite(SPRITE_WEAPON, headBottom, std::string()); |
1079 |
|
|
dstBeing->updateSprite(SPRITE_HEAD_BOTTOM, headMid, std::string()); |
1080 |
|
|
dstBeing->updateSprite(SPRITE_CLOTHES_COLOR, headTop, std::string()); |
1081 |
|
|
dstBeing->updateSprite(SPRITE_HAIR, shoes, std::string()); |
1082 |
|
|
dstBeing->updateSprite(SPRITE_SHOES, gloves, std::string()); |
1083 |
|
|
dstBeing->updateSprite(SPRITE_BODY, weapon, std::string()); |
1084 |
|
|
dstBeing->setWeaponId(weapon); |
1085 |
|
|
dstBeing->updateSprite(SPRITE_FLOOR, shield, std::string()); |
1086 |
|
|
} |
1087 |
|
|
else if (dstBeing->getType() == ActorType::Npc |
1088 |
|
|
&& serverFeatures->haveNpcGender()) |
1089 |
|
|
{ |
1090 |
|
|
setServerGender(dstBeing, gender); |
1091 |
|
|
} |
1092 |
|
|
|
1093 |
|
|
uint16_t srcX; |
1094 |
|
|
uint16_t srcY; |
1095 |
|
|
uint16_t dstX; |
1096 |
|
|
uint16_t dstY; |
1097 |
|
|
msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path"); |
1098 |
|
|
if (disguiseId == 0) |
1099 |
|
|
{ |
1100 |
|
|
dstBeing->setAction(BeingAction::STAND, 0); |
1101 |
|
|
dstBeing->setTileCoords(srcX, srcY); |
1102 |
|
|
if (serverFeatures->haveMove3()) |
1103 |
|
|
dstBeing->setCachedDestination(dstX, dstY); |
1104 |
|
|
else |
1105 |
|
|
dstBeing->setDestination(dstX, dstY); |
1106 |
|
|
} |
1107 |
|
|
|
1108 |
|
|
msg.readUInt8("unknown"); |
1109 |
|
|
msg.readUInt8("unknown"); |
1110 |
|
|
msg.readUInt8("unknown"); |
1111 |
|
|
msg.readUInt8("unknown"); |
1112 |
|
|
msg.readUInt8("unknown"); |
1113 |
|
|
|
1114 |
|
|
dstBeing->setStatusEffectOpitons(option, |
1115 |
|
|
opt1, |
1116 |
|
|
opt2, |
1117 |
|
|
opt3); |
1118 |
|
|
BLOCK_END("BeingRecv::processBeingVisibleOrMove") |
1119 |
|
|
} |
1120 |
|
|
|
1121 |
|
|
void BeingRecv::processBeingSpawn(Net::MessageIn &msg) |
1122 |
|
|
{ |
1123 |
|
|
BLOCK_START("BeingRecv::processBeingSpawn") |
1124 |
|
|
// skipping this packet |
1125 |
|
|
Ea::BeingRecv::mSpawnId = msg.readBeingId("being id"); |
1126 |
|
|
msg.readInt16("speed"); |
1127 |
|
|
msg.readInt16("opt1"); |
1128 |
|
|
msg.readInt16("opt2"); |
1129 |
|
|
msg.readInt16("option"); |
1130 |
|
|
msg.readInt16("disguise"); |
1131 |
|
|
msg.skip(25, "unused"); |
1132 |
|
|
BLOCK_END("BeingRecv::processBeingSpawn") |
1133 |
|
|
} |
1134 |
|
|
|
1135 |
|
|
void BeingRecv::processSkillCasting(Net::MessageIn &msg) |
1136 |
|
|
{ |
1137 |
|
|
msg.readInt32("src id"); |
1138 |
|
|
msg.readInt32("dst id"); |
1139 |
|
|
msg.readInt16("dst x"); |
1140 |
|
|
msg.readInt16("dst y"); |
1141 |
|
|
msg.readInt16("skill num"); |
1142 |
|
|
msg.readInt32("skill get p1"); |
1143 |
|
|
msg.readInt32("cast time"); |
1144 |
|
|
} |
1145 |
|
|
|
1146 |
|
|
void BeingRecv::processBeingStatusChange(Net::MessageIn &msg) |
1147 |
|
|
{ |
1148 |
|
|
BLOCK_START("BeingRecv::processBeingStatusChange") |
1149 |
|
|
if (actorManager == nullptr) |
1150 |
|
|
{ |
1151 |
|
|
BLOCK_END("BeingRecv::processBeingStatusChange") |
1152 |
|
|
return; |
1153 |
|
|
} |
1154 |
|
|
|
1155 |
|
|
// Status change |
1156 |
|
|
const uint16_t status = msg.readInt16("status"); |
1157 |
|
|
const BeingId id = msg.readBeingId("being id"); |
1158 |
|
|
const Enable flag = fromBool( |
1159 |
|
|
msg.readUInt8("flag: 0: stop, 1: start"), Enable); |
1160 |
|
|
|
1161 |
|
|
Being *const dstBeing = actorManager->findBeing(id); |
1162 |
|
|
if (dstBeing != nullptr) |
1163 |
|
|
{ |
1164 |
|
|
// dont know on legacy servers is effect really started |
1165 |
|
|
// or not. Because this always sending IsStart_true |
1166 |
|
|
dstBeing->setStatusEffect(status, flag, IsStart_true); |
1167 |
|
|
} |
1168 |
|
|
BLOCK_END("BeingRecv::processBeingStatusChange") |
1169 |
|
|
} |
1170 |
|
|
|
1171 |
|
|
void BeingRecv::processBeingMove2(Net::MessageIn &msg) |
1172 |
|
|
{ |
1173 |
|
|
BLOCK_START("BeingRecv::processBeingMove2") |
1174 |
|
|
if (actorManager == nullptr) |
1175 |
|
|
{ |
1176 |
|
|
BLOCK_END("BeingRecv::processBeingMove2") |
1177 |
|
|
return; |
1178 |
|
|
} |
1179 |
|
|
|
1180 |
|
|
/* |
1181 |
|
|
* A simplified movement packet, used by the |
1182 |
|
|
* later versions of eAthena for both mobs and |
1183 |
|
|
* players |
1184 |
|
|
*/ |
1185 |
|
|
Being *const dstBeing = actorManager->findBeing( |
1186 |
|
|
msg.readBeingId("being id")); |
1187 |
|
|
|
1188 |
|
|
/* |
1189 |
|
|
* This packet doesn't have enough info to actually |
1190 |
|
|
* create a new being, so if the being isn't found, |
1191 |
|
|
* we'll just pretend the packet didn't happen |
1192 |
|
|
*/ |
1193 |
|
|
|
1194 |
|
|
if (dstBeing == nullptr) |
1195 |
|
|
{ |
1196 |
|
|
BLOCK_END("BeingRecv::processBeingMove2") |
1197 |
|
|
return; |
1198 |
|
|
} |
1199 |
|
|
|
1200 |
|
|
uint16_t srcX; |
1201 |
|
|
uint16_t srcY; |
1202 |
|
|
uint16_t dstX; |
1203 |
|
|
uint16_t dstY; |
1204 |
|
|
msg.readCoordinatePair(srcX, srcY, dstX, dstY, "move path"); |
1205 |
|
|
msg.readInt32("tick"); |
1206 |
|
|
|
1207 |
|
|
dstBeing->setAction(BeingAction::STAND, 0); |
1208 |
|
|
dstBeing->setTileCoords(srcX, srcY); |
1209 |
|
|
dstBeing->setDestination(dstX, dstY); |
1210 |
|
|
if (dstBeing->getType() == ActorType::Player) |
1211 |
|
|
dstBeing->setMoveTime(); |
1212 |
|
|
BLOCK_END("BeingRecv::processBeingMove2") |
1213 |
|
|
} |
1214 |
|
|
|
1215 |
|
|
void BeingRecv::processBeingChangeDirection(Net::MessageIn &msg) |
1216 |
|
|
{ |
1217 |
|
|
BLOCK_START("BeingRecv::processBeingChangeDirection") |
1218 |
|
|
if (actorManager == nullptr) |
1219 |
|
|
{ |
1220 |
|
|
BLOCK_END("BeingRecv::processBeingChangeDirection") |
1221 |
|
|
return; |
1222 |
|
|
} |
1223 |
|
|
|
1224 |
|
|
Being *const dstBeing = actorManager->findBeing( |
1225 |
|
|
msg.readBeingId("being id")); |
1226 |
|
|
|
1227 |
|
|
if (dstBeing == nullptr) |
1228 |
|
|
{ |
1229 |
|
|
DEBUGLOGSTR("invisible player?"); |
1230 |
|
|
msg.readInt16("unused"); |
1231 |
|
|
msg.readUInt8("direction"); |
1232 |
|
|
BLOCK_END("BeingRecv::processBeingChangeDirection"); |
1233 |
|
|
return; |
1234 |
|
|
} |
1235 |
|
|
|
1236 |
|
|
msg.readInt16("unused"); |
1237 |
|
|
|
1238 |
|
|
const uint8_t dir = Net::MessageIn::fromServerDirection( |
1239 |
|
|
CAST_U8(msg.readUInt8("direction") & 0x0FU)); |
1240 |
|
|
dstBeing->setDirection(dir); |
1241 |
|
|
if (localPlayer != nullptr) |
1242 |
|
|
localPlayer->imitateDirection(dstBeing, dir); |
1243 |
|
|
BLOCK_END("BeingRecv::processBeingChangeDirection") |
1244 |
|
|
} |
1245 |
|
|
|
1246 |
|
|
void BeingRecv::processPlayerStatusChange(Net::MessageIn &msg) |
1247 |
|
|
{ |
1248 |
|
|
BLOCK_START("BeingRecv::processPlayerStop") |
1249 |
|
|
if (actorManager == nullptr) |
1250 |
|
|
{ |
1251 |
|
|
BLOCK_END("BeingRecv::processPlayerStop") |
1252 |
|
|
return; |
1253 |
|
|
} |
1254 |
|
|
|
1255 |
|
|
// Change in players' flags |
1256 |
|
|
const BeingId id = msg.readBeingId("account id"); |
1257 |
|
|
Being *const dstBeing = actorManager->findBeing(id); |
1258 |
|
|
if (dstBeing == nullptr) |
1259 |
|
|
{ |
1260 |
|
|
DEBUGLOGSTR("invisible player?"); |
1261 |
|
|
msg.readInt16("stun mode"); |
1262 |
|
|
msg.readInt16("status effect"); |
1263 |
|
|
msg.readInt16("opt?"); |
1264 |
|
|
msg.readUInt8("Unused?"); |
1265 |
|
|
return; |
1266 |
|
|
} |
1267 |
|
|
|
1268 |
|
|
const uint32_t opt1 = msg.readInt16("opt1"); |
1269 |
|
|
const uint32_t opt2 = msg.readInt16("opt2"); |
1270 |
|
|
const uint32_t option = msg.readInt16("option"); |
1271 |
|
|
msg.readUInt8("Unused?"); |
1272 |
|
|
|
1273 |
|
|
dstBeing->setStatusEffectOpitons(option, |
1274 |
|
|
opt1, |
1275 |
|
|
opt2); |
1276 |
|
|
BLOCK_END("BeingRecv::processPlayerStop") |
1277 |
|
|
} |
1278 |
|
|
|
1279 |
|
|
void BeingRecv::processBeingResurrect(Net::MessageIn &msg) |
1280 |
|
|
{ |
1281 |
|
|
BLOCK_START("BeingRecv::processBeingResurrect") |
1282 |
|
|
if (actorManager == nullptr || localPlayer == nullptr) |
1283 |
|
|
{ |
1284 |
|
|
BLOCK_END("BeingRecv::processBeingResurrect") |
1285 |
|
|
return; |
1286 |
|
|
} |
1287 |
|
|
|
1288 |
|
|
// A being changed mortality status |
1289 |
|
|
|
1290 |
|
|
const BeingId id = msg.readBeingId("being id"); |
1291 |
|
|
Being *const dstBeing = actorManager->findBeing(id); |
1292 |
|
|
if (dstBeing == nullptr) |
1293 |
|
|
{ |
1294 |
|
|
DEBUGLOGSTR("insible player?"); |
1295 |
|
|
msg.readInt16("flag?"); |
1296 |
|
|
BLOCK_END("BeingRecv::processBeingResurrect") |
1297 |
|
|
return; |
1298 |
|
|
} |
1299 |
|
|
|
1300 |
|
|
// If this is player's current target, clear it. |
1301 |
|
|
if (dstBeing == localPlayer->getTarget()) |
1302 |
|
|
localPlayer->stopAttack(false); |
1303 |
|
|
if (dstBeing == localPlayer && |
1304 |
|
|
deathNotice != nullptr) |
1305 |
|
|
{ |
1306 |
|
|
deathNotice->scheduleDelete(); |
1307 |
|
|
deathNotice = nullptr; |
1308 |
|
|
} |
1309 |
|
|
|
1310 |
|
|
if (msg.readInt16("flag?") == 1) |
1311 |
|
|
dstBeing->setAction(BeingAction::STAND, 0); |
1312 |
|
|
BLOCK_END("BeingRecv::processBeingResurrect") |
1313 |
|
|
} |
1314 |
|
|
|
1315 |
|
|
void BeingRecv::processPlayerGuilPartyInfo(Net::MessageIn &msg) |
1316 |
|
|
{ |
1317 |
|
|
BLOCK_START("BeingRecv::processPlayerGuilPartyInfo") |
1318 |
|
|
if (actorManager == nullptr) |
1319 |
|
|
{ |
1320 |
|
|
BLOCK_END("BeingRecv::processPlayerGuilPartyInfo") |
1321 |
|
|
return; |
1322 |
|
|
} |
1323 |
|
|
|
1324 |
|
|
Being *const dstBeing = actorManager->findBeing( |
1325 |
|
|
msg.readBeingId("being id")); |
1326 |
|
|
|
1327 |
|
|
if (dstBeing != nullptr) |
1328 |
|
|
{ |
1329 |
|
|
dstBeing->setPartyName(msg.readString(24, "party name")); |
1330 |
|
|
if ((guildManager == nullptr) || !GuildManager::getEnableGuildBot()) |
1331 |
|
|
{ |
1332 |
|
|
dstBeing->setGuildName(msg.readString(24, "guild name")); |
1333 |
|
|
dstBeing->setGuildPos(msg.readString(24, "guild pos")); |
1334 |
|
|
} |
1335 |
|
|
else |
1336 |
|
|
{ |
1337 |
|
|
msg.readString(24, "guild name"); |
1338 |
|
|
msg.readString(24, "guild pos"); |
1339 |
|
|
} |
1340 |
|
|
dstBeing->addToCache(); |
1341 |
|
|
msg.readString(24, "?"); |
1342 |
|
|
} |
1343 |
|
|
else |
1344 |
|
|
{ |
1345 |
|
|
msg.readString(24, "party name"); |
1346 |
|
|
msg.readString(24, "guild name"); |
1347 |
|
|
msg.readString(24, "guild pos"); |
1348 |
|
|
msg.readString(24, "?"); |
1349 |
|
|
} |
1350 |
|
|
BLOCK_END("BeingRecv::processPlayerGuilPartyInfo") |
1351 |
|
|
} |
1352 |
|
|
|
1353 |
|
|
void BeingRecv::processBeingSelfEffect(Net::MessageIn &msg) |
1354 |
|
|
{ |
1355 |
|
|
BLOCK_START("BeingRecv::processBeingSelfEffect") |
1356 |
|
|
if ((effectManager == nullptr) || (actorManager == nullptr)) |
1357 |
|
|
{ |
1358 |
|
|
BLOCK_END("BeingRecv::processBeingSelfEffect") |
1359 |
|
|
return; |
1360 |
|
|
} |
1361 |
|
|
|
1362 |
|
|
const BeingId id = msg.readBeingId("being id"); |
1363 |
|
|
Being *const being = actorManager->findBeing(id); |
1364 |
|
|
if (being == nullptr) |
1365 |
|
|
{ |
1366 |
|
|
DEBUGLOGSTR("insible player?"); |
1367 |
|
|
msg.readInt32("effect type"); |
1368 |
|
|
BLOCK_END("BeingRecv::processBeingSelfEffect") |
1369 |
|
|
return; |
1370 |
|
|
} |
1371 |
|
|
|
1372 |
|
|
const int effectType = msg.readInt32("effect type"); |
1373 |
|
|
|
1374 |
|
|
if (ParticleEngine::enabled) |
1375 |
|
|
effectManager->trigger(effectType, being, 0); |
1376 |
|
|
|
1377 |
|
|
// +++ need dehard code effectType == 3 |
1378 |
|
|
if (effectType == 3 && being->getType() == ActorType::Player |
1379 |
|
|
&& (socialWindow != nullptr)) |
1380 |
|
|
{ // reset received damage |
1381 |
|
|
socialWindow->resetDamage(being->getName()); |
1382 |
|
|
} |
1383 |
|
|
BLOCK_END("BeingRecv::processBeingSelfEffect") |
1384 |
|
|
} |
1385 |
|
|
|
1386 |
|
|
void BeingRecv::processSkillCastCancel(Net::MessageIn &msg) |
1387 |
|
|
{ |
1388 |
|
|
msg.readInt32("skill id"); |
1389 |
|
|
} |
1390 |
|
|
|
1391 |
|
|
void BeingRecv::processIpResponse(Net::MessageIn &msg) |
1392 |
|
|
{ |
1393 |
|
|
BLOCK_START("BeingRecv::processIpResponse") |
1394 |
|
|
if (actorManager == nullptr) |
1395 |
|
|
{ |
1396 |
|
|
BLOCK_END("BeingRecv::processIpResponse") |
1397 |
|
|
return; |
1398 |
|
|
} |
1399 |
|
|
|
1400 |
|
|
Being *const dstBeing = actorManager->findBeing( |
1401 |
|
|
msg.readBeingId("being id")); |
1402 |
|
|
if (dstBeing != nullptr) |
1403 |
|
|
{ |
1404 |
|
|
const std::string ip = ipToString(msg.readInt32("ip address")); |
1405 |
|
|
dstBeing->setIp(ip); |
1406 |
|
|
} |
1407 |
|
|
else |
1408 |
|
|
{ |
1409 |
|
|
msg.readInt32("ip address"); |
1410 |
|
|
DEBUGLOGSTR("invisible player?"); |
1411 |
|
|
} |
1412 |
|
|
|
1413 |
|
|
BLOCK_END("BeingRecv::processIpResponse") |
1414 |
|
|
} |
1415 |
|
|
|
1416 |
|
|
void BeingRecv::processPvpSet(Net::MessageIn &msg) |
1417 |
|
|
{ |
1418 |
|
|
BLOCK_START("BeingRecv::processPvpSet") |
1419 |
|
|
const BeingId id = msg.readBeingId("being id"); |
1420 |
|
|
const int rank = msg.readInt32("rank"); |
1421 |
|
|
int teamId = 0; |
1422 |
|
|
teamId = msg.readInt32("team"); |
1423 |
|
|
if (actorManager != nullptr) |
1424 |
|
|
{ |
1425 |
|
|
Being *const dstBeing = actorManager->findBeing(id); |
1426 |
|
|
if (dstBeing != nullptr) |
1427 |
|
|
{ |
1428 |
|
|
dstBeing->setPvpRank(rank); |
1429 |
|
|
dstBeing->setTeamId(CAST_U16(teamId)); |
1430 |
|
|
dstBeing->addToCache(); |
1431 |
|
|
} |
1432 |
|
|
} |
1433 |
|
|
BLOCK_END("BeingRecv::processPvpSet") |
1434 |
|
|
} |
1435 |
|
|
|
1436 |
|
|
void BeingRecv::applyPlayerAction(Net::MessageIn &msg, |
1437 |
|
|
Being *const being, |
1438 |
|
|
const uint8_t type) |
1439 |
|
|
{ |
1440 |
|
|
if (being == nullptr) |
1441 |
|
|
return; |
1442 |
|
|
switch (type) |
1443 |
|
|
{ |
1444 |
|
|
case 0: |
1445 |
|
|
being->setAction(BeingAction::STAND, 0); |
1446 |
|
|
localPlayer->imitateAction(being, BeingAction::STAND); |
1447 |
|
|
break; |
1448 |
|
|
|
1449 |
|
|
case 1: |
1450 |
|
|
if (being->getCurrentAction() != BeingAction::DEAD) |
1451 |
|
|
{ |
1452 |
|
|
being->setAction(BeingAction::DEAD, 0); |
1453 |
|
|
being->recalcSpritesOrder(); |
1454 |
|
|
} |
1455 |
|
|
break; |
1456 |
|
|
|
1457 |
|
|
case 2: |
1458 |
|
|
being->setAction(BeingAction::SIT, 0); |
1459 |
|
|
localPlayer->imitateAction(being, BeingAction::SIT); |
1460 |
|
|
break; |
1461 |
|
|
|
1462 |
|
|
default: |
1463 |
|
|
UNIMPLEMENTEDPACKETFIELD(type); |
1464 |
|
|
break; |
1465 |
|
|
} |
1466 |
|
|
} |
1467 |
|
|
|
1468 |
|
|
void BeingRecv::processSkillDamage(Net::MessageIn &msg) |
1469 |
|
|
{ |
1470 |
|
|
BLOCK_START("BeingRecv::processSkillDamage") |
1471 |
|
|
if (actorManager == nullptr) |
1472 |
|
|
{ |
1473 |
|
|
BLOCK_END("BeingRecv::processSkillDamage") |
1474 |
|
|
return; |
1475 |
|
|
} |
1476 |
|
|
|
1477 |
|
|
const int id = msg.readInt16("skill id"); |
1478 |
|
|
Being *const srcBeing = actorManager->findBeing( |
1479 |
|
|
msg.readBeingId("src being id")); |
1480 |
|
|
Being *const dstBeing = actorManager->findBeing( |
1481 |
|
|
msg.readBeingId("dst being id")); |
1482 |
|
|
msg.readInt32("tick"); |
1483 |
|
|
msg.readInt32("src speed"); |
1484 |
|
|
msg.readInt32("dst speed"); |
1485 |
|
|
const int param1 = msg.readInt32("damage"); |
1486 |
|
|
const int level = msg.readInt16("skill level"); |
1487 |
|
|
msg.readInt16("div"); |
1488 |
|
|
msg.readUInt8("skill hit/type?"); |
1489 |
|
|
if (srcBeing != nullptr) |
1490 |
|
|
srcBeing->handleSkill(dstBeing, param1, id, level); |
1491 |
|
|
if (dstBeing != nullptr) |
1492 |
|
|
dstBeing->takeDamage(srcBeing, param1, AttackType::SKILL, id, level); |
1493 |
|
|
BLOCK_END("BeingRecv::processSkillDamage") |
1494 |
|
|
} |
1495 |
|
|
|
1496 |
|
|
void BeingRecv::setServerGender(Being *const being, |
1497 |
|
|
const uint8_t gender) |
1498 |
|
|
{ |
1499 |
|
|
if (being == nullptr) |
1500 |
|
|
return; |
1501 |
|
|
switch (gender) |
1502 |
|
|
{ |
1503 |
|
|
case 2: |
1504 |
|
|
being->setGender(Gender::FEMALE); |
1505 |
|
|
break; |
1506 |
|
|
case 3: |
1507 |
|
|
being->setGender(Gender::MALE); |
1508 |
|
|
break; |
1509 |
|
|
default: |
1510 |
|
|
being->setGender(Gender::UNSPECIFIED); |
1511 |
|
|
break; |
1512 |
|
|
} |
1513 |
|
|
} |
1514 |
|
|
|
1515 |
|
2 |
} // namespace TmwAthena |