00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "net/ea/beinghandler.h"
00023
00024 #include "net/ea/protocol.h"
00025
00026 #include "net/messagein.h"
00027 #include "net/messageout.h"
00028
00029 #include "being.h"
00030 #include "beingmanager.h"
00031 #include "effectmanager.h"
00032 #include "game.h"
00033 #include "localplayer.h"
00034 #include "log.h"
00035 #include "npc.h"
00036 #include "player_relations.h"
00037
00038 #include "gui/npc_text.h"
00039
00040 #include <iostream>
00041
00042 extern NpcTextDialog *npcTextDialog;
00043
00044 namespace EAthena {
00045
00046 const int EMOTION_TIME = 150;
00048 BeingHandler::BeingHandler(bool enableSync):
00049 mSync(enableSync)
00050 {
00051 static const Uint16 _messages[] = {
00052 SMSG_BEING_VISIBLE,
00053 SMSG_BEING_MOVE,
00054 SMSG_BEING_MOVE2,
00055 SMSG_BEING_REMOVE,
00056 SMSG_BEING_ACTION,
00057 SMSG_BEING_SELFEFFECT,
00058 SMSG_BEING_EMOTION,
00059 SMSG_BEING_CHANGE_LOOKS,
00060 SMSG_BEING_CHANGE_LOOKS2,
00061 SMSG_BEING_NAME_RESPONSE,
00062 SMSG_BEING_CHANGE_DIRECTION,
00063 SMSG_PLAYER_UPDATE_1,
00064 SMSG_PLAYER_UPDATE_2,
00065 SMSG_PLAYER_MOVE,
00066 SMSG_PLAYER_STOP,
00067 SMSG_PLAYER_MOVE_TO_ATTACK,
00068 SMSG_PLAYER_STATUS_CHANGE,
00069 SMSG_BEING_STATUS_CHANGE,
00070 0
00071 };
00072 handledMessages = _messages;
00073 }
00074
00075 Being *createBeing(int id, short job)
00076 {
00077 Being::Type type = Being::UNKNOWN;
00078 if (job <= 25 || (job >= 4001 && job <= 4049))
00079 type = Being::PLAYER;
00080 else if (job >= 46 && job <= 1000)
00081 type = Being::NPC;
00082 else if (job > 1000 && job <= 2000)
00083 {
00084 type = Being::MONSTER;
00085 job -= 1002;
00086 }
00087
00088 Being *being = beingManager->createBeing(id, type, job);
00089
00090 if (type == Being::PLAYER || type == Being::NPC)
00091 {
00092 MessageOut outMsg(0x0094);
00093 outMsg.writeInt32(id);
00094 }
00095
00096 return being;
00097 }
00098
00099 void BeingHandler::handleMessage(MessageIn &msg)
00100 {
00101 int id;
00102 short job, speed;
00103 Uint16 headTop, headMid, headBottom;
00104 Uint16 shoes, gloves;
00105 Uint16 weapon, shield;
00106 Uint16 gmstatus;
00107 int param1;
00108 int stunMode;
00109 Uint32 statusEffects;
00110 int type;
00111 Uint16 status;
00112 Being *srcBeing, *dstBeing;
00113 int hairStyle, hairColor, flag;
00114
00115 switch (msg.getId())
00116 {
00117 case SMSG_BEING_VISIBLE:
00118 case SMSG_BEING_MOVE:
00119
00120 id = msg.readInt32();
00121 speed = msg.readInt16();
00122 stunMode = msg.readInt16();
00123 statusEffects = msg.readInt16();
00124 statusEffects |= ((Uint32)msg.readInt16()) << 16;
00125 job = msg.readInt16();
00126
00127 dstBeing = beingManager->findBeing(id);
00128
00129 if (!dstBeing)
00130 {
00131
00132
00133 if (job == 0 && id >= 110000000)
00134 {
00135 break;
00136 }
00137
00138 dstBeing = createBeing(id, job);
00139 }
00140
00141
00142 if (dstBeing->getType() == Being::MONSTER)
00143 {
00144 job -= 1002;
00145 }
00146
00147 if (msg.getId() == 0x0078)
00148 {
00149 dstBeing->clearPath();
00150 dstBeing->mFrame = 0;
00151 dstBeing->mWalkTime = tick_time;
00152 dstBeing->setAction(Being::STAND);
00153 }
00154
00155
00156
00157 if (speed == 0) { speed = 150; }
00158
00159 dstBeing->setWalkSpeed(speed);
00160 dstBeing->mJob = job;
00161 hairStyle = msg.readInt16();
00162 dstBeing->setSprite(Being::WEAPON_SPRITE, msg.readInt16());
00163 headBottom = msg.readInt16();
00164
00165 if (msg.getId() == SMSG_BEING_MOVE)
00166 {
00167 msg.readInt32();
00168 }
00169
00170 dstBeing->setSprite(Being::SHIELD_SPRITE, msg.readInt16());
00171 headTop = msg.readInt16();
00172 headMid = msg.readInt16();
00173 hairColor = msg.readInt16();
00174 shoes = msg.readInt16();
00175 gloves = msg.readInt16();
00176 msg.readInt16();
00177 msg.readInt16();
00178 msg.readInt16();
00179 msg.readInt16();
00180 dstBeing->setStatusEffectBlock(32, msg.readInt16());
00181 msg.readInt8();
00182 dstBeing->setGender(
00183 (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE);
00184
00185
00186 dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
00187 dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
00188 dstBeing->setSprite(Being::HAT_SPRITE, headTop);
00189 dstBeing->setSprite(Being::SHOE_SPRITE, shoes);
00190 dstBeing->setSprite(Being::GLOVES_SPRITE, gloves);
00191 dstBeing->setHairStyle(hairStyle, hairColor);
00192
00193 if (msg.getId() == SMSG_BEING_MOVE)
00194 {
00195 Uint16 srcX, srcY, dstX, dstY;
00196 msg.readCoordinatePair(srcX, srcY, dstX, dstY);
00197 dstBeing->setAction(Being::STAND);
00198 dstBeing->mX = srcX;
00199 dstBeing->mY = srcY;
00200 dstBeing->setDestination(dstX, dstY);
00201 }
00202 else
00203 {
00204 Uint8 dir;
00205 msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir);
00206 dstBeing->setDirection(dir);
00207 }
00208
00209 msg.readInt8();
00210 msg.readInt8();
00211 msg.readInt8();
00212
00213 dstBeing->setStunMode(stunMode);
00214 dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
00215 dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
00216 break;
00217
00218 case SMSG_BEING_MOVE2:
00219
00220
00221
00222
00223
00224 dstBeing = beingManager->findBeing(msg.readInt32());
00225
00226 Uint16 srcX, srcY, dstX, dstY;
00227 msg.readCoordinatePair(srcX, srcY, dstX, dstY);
00228 msg.readInt32();
00229
00230
00231
00232
00233
00234
00235
00236 if (dstBeing) {
00237 dstBeing->setAction(Being::STAND);
00238 dstBeing->mX = srcX;
00239 dstBeing->mY = srcY;
00240 dstBeing->setDestination(dstX, dstY);
00241 }
00242
00243 break;
00244
00245 case SMSG_BEING_REMOVE:
00246
00247 id = msg.readInt32();
00248
00249 if (id == current_npc)
00250 npcTextDialog->showCloseButton();
00251
00252 dstBeing = beingManager->findBeing(id);
00253
00254 if (!dstBeing)
00255 break;
00256
00257
00258 if (dstBeing == player_node->getTarget())
00259 player_node->stopAttack();
00260
00261 if (msg.readInt8() == 1)
00262 dstBeing->setAction(Being::DEAD);
00263 else
00264 beingManager->destroyBeing(dstBeing);
00265
00266 break;
00267
00268 case SMSG_BEING_ACTION:
00269 srcBeing = beingManager->findBeing(msg.readInt32());
00270 dstBeing = beingManager->findBeing(msg.readInt32());
00271 msg.readInt32();
00272 msg.readInt32();
00273 msg.readInt32();
00274 param1 = msg.readInt16();
00275 msg.readInt16();
00276 type = msg.readInt8();
00277 msg.readInt16();
00278
00279 switch (type)
00280 {
00281 case Being::HIT:
00282 case Being::CRITICAL:
00283 case Being::MULTI:
00284 case Being::REFLECT:
00285 case Being::FLEE:
00286 if (dstBeing)
00287 dstBeing->takeDamage(srcBeing, param1,
00288 (Being::AttackType)type);
00289 if (srcBeing)
00290 srcBeing->handleAttack(dstBeing, param1,
00291 (Being::AttackType)type);
00292 break;
00293
00294 case 0x02:
00295 if (srcBeing)
00296 {
00297 srcBeing->mFrame = 0;
00298 srcBeing->setAction(Being::SIT);
00299 }
00300 break;
00301
00302 case 0x03:
00303 if (srcBeing)
00304 {
00305 srcBeing->mFrame = 0;
00306 srcBeing->setAction(Being::STAND);
00307 }
00308 break;
00309 }
00310 break;
00311
00312 case SMSG_BEING_SELFEFFECT: {
00313 id = (Uint32)msg.readInt32();
00314 if (!beingManager->findBeing(id))
00315 break;
00316
00317 int effectType = msg.readInt32();
00318 Being* being = beingManager->findBeing(id);
00319
00320 effectManager->trigger(effectType, being);
00321
00322 break;
00323 }
00324
00325 case SMSG_BEING_EMOTION:
00326 if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
00327 {
00328 break;
00329 }
00330
00331 if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE))
00332 dstBeing->setEmote(msg.readInt8(), EMOTION_TIME);
00333
00334 break;
00335
00336 case SMSG_BEING_CHANGE_LOOKS:
00337 case SMSG_BEING_CHANGE_LOOKS2:
00338 {
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
00352 {
00353 break;
00354 }
00355
00356 int type = msg.readInt8();
00357 int id = 0;
00358 int id2 = 0;
00359
00360 if (msg.getId() == SMSG_BEING_CHANGE_LOOKS) {
00361 id = msg.readInt8();
00362 } else {
00363 id = msg.readInt16();
00364 id2 = msg.readInt16();
00365 }
00366
00367 switch (type) {
00368 case 1:
00369 dstBeing->setHairStyle(id, -1);
00370 break;
00371 case 2:
00372 dstBeing->setSprite(Being::WEAPON_SPRITE, id);
00373 dstBeing->setSprite(Being::SHIELD_SPRITE, id2);
00374 break;
00375 case 3:
00376 dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, id);
00377 break;
00378 case 4:
00379 dstBeing->setSprite(Being::HAT_SPRITE, id);
00380 break;
00381 case 5:
00382 dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, id);
00383 break;
00384 case 6:
00385 dstBeing->setHairStyle(-1, id);
00386 break;
00387 case 8:
00388 dstBeing->setSprite(Being::SHIELD_SPRITE, id);
00389 break;
00390 case 9:
00391 dstBeing->setSprite(Being::SHOE_SPRITE, id);
00392 break;
00393 case 10:
00394 dstBeing->setSprite(Being::GLOVES_SPRITE, id);
00395 break;
00396 case 11:
00397 dstBeing->setSprite(Being::CAPE_SPRITE, id);
00398 break;
00399 case 12:
00400 dstBeing->setSprite(Being::MISC1_SPRITE, id);
00401 break;
00402 case 13:
00403 dstBeing->setSprite(Being::MISC2_SPRITE, id);
00404 break;
00405 default:
00406 logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: "
00407 "%d, id: %d", type, id);
00408 break;
00409 }
00410 }
00411 break;
00412
00413 case SMSG_BEING_NAME_RESPONSE:
00414 if ((dstBeing = beingManager->findBeing(msg.readInt32())))
00415 {
00416 dstBeing->setName(msg.readString(24));
00417 }
00418 break;
00419
00420 case SMSG_BEING_CHANGE_DIRECTION:
00421 if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
00422 {
00423 break;
00424 }
00425
00426 msg.readInt16();
00427
00428 dstBeing->setDirection(msg.readInt8());
00429
00430 break;
00431
00432 case SMSG_PLAYER_UPDATE_1:
00433 case SMSG_PLAYER_UPDATE_2:
00434 case SMSG_PLAYER_MOVE:
00435
00436 id = msg.readInt32();
00437 speed = msg.readInt16();
00438 stunMode = msg.readInt16();
00439 statusEffects = msg.readInt16();
00440 statusEffects |= ((Uint32) msg.readInt16())
00441 << 16;
00442 job = msg.readInt16();
00443
00444 dstBeing = beingManager->findBeing(id);
00445
00446 if (!dstBeing)
00447 {
00448 dstBeing = createBeing(id, job);
00449 }
00450
00451
00452 if (dstBeing->getType() == Being::MONSTER)
00453 {
00454 job -= 1002;
00455 }
00456
00457 dstBeing->setWalkSpeed(speed);
00458 dstBeing->mJob = job;
00459 hairStyle = msg.readInt16();
00460 weapon = msg.readInt16();
00461 shield = msg.readInt16();
00462 headBottom = msg.readInt16();
00463
00464 if (msg.getId() == SMSG_PLAYER_MOVE)
00465 {
00466 msg.readInt32();
00467 }
00468
00469 headTop = msg.readInt16();
00470 headMid = msg.readInt16();
00471 hairColor = msg.readInt16();
00472 msg.readInt16();
00473 msg.readInt16();
00474 msg.readInt32();
00475 msg.readInt16();
00476 msg.readInt16();
00477 dstBeing->setStatusEffectBlock(32, msg.readInt16());
00478 msg.readInt8();
00479 dstBeing->setGender(
00480 (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE);
00481
00482
00483 dstBeing->setSprite(Being::WEAPON_SPRITE, weapon);
00484 dstBeing->setSprite(Being::SHIELD_SPRITE, shield);
00485 dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
00486 dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
00487 dstBeing->setSprite(Being::HAT_SPRITE, headTop);
00488
00489
00490
00491 dstBeing->setHairStyle(hairStyle, hairColor);
00492
00493 if (msg.getId() == SMSG_PLAYER_MOVE)
00494 {
00495 Uint16 srcX, srcY, dstX, dstY;
00496 msg.readCoordinatePair(srcX, srcY, dstX, dstY);
00497 dstBeing->mX = srcX;
00498 dstBeing->mY = srcY;
00499 dstBeing->setDestination(dstX, dstY);
00500 }
00501 else
00502 {
00503 Uint8 dir;
00504 msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir);
00505 dstBeing->setDirection(dir);
00506 }
00507
00508 gmstatus = msg.readInt16();
00509 if (gmstatus & 0x80)
00510 dstBeing->setGM();
00511
00512 if (msg.getId() == SMSG_PLAYER_UPDATE_1)
00513 {
00514 switch (msg.readInt8())
00515 {
00516 case 1:
00517 dstBeing->setAction(Being::DEAD);
00518 break;
00519
00520 case 2:
00521 dstBeing->setAction(Being::SIT);
00522 break;
00523 }
00524 }
00525 else if (msg.getId() == SMSG_PLAYER_MOVE)
00526 {
00527 msg.readInt8();
00528 }
00529
00530 msg.readInt8();
00531 msg.readInt8();
00532
00533 dstBeing->mWalkTime = tick_time;
00534 dstBeing->mFrame = 0;
00535
00536 dstBeing->setStunMode(stunMode);
00537 dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
00538 dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
00539 break;
00540
00541 case SMSG_PLAYER_STOP:
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 id = msg.readInt32();
00555 if (mSync || id != player_node->getId()) {
00556 dstBeing = beingManager->findBeing(id);
00557 if (dstBeing) {
00558 dstBeing->mX = msg.readInt16();
00559 dstBeing->mY = msg.readInt16();
00560 if (dstBeing->mAction == Being::WALK) {
00561 dstBeing->mFrame = 0;
00562 dstBeing->setAction(Being::STAND);
00563 }
00564 }
00565 }
00566 break;
00567
00568 case SMSG_PLAYER_MOVE_TO_ATTACK:
00569
00570
00571
00572
00573
00574
00575 break;
00576
00577 case SMSG_PLAYER_STATUS_CHANGE:
00578
00579 id = msg.readInt32();
00580 dstBeing = beingManager->findBeing(id);
00581 stunMode = msg.readInt16();
00582 statusEffects = msg.readInt16();
00583 statusEffects |= ((Uint32) msg.readInt16()) << 16;
00584 msg.readInt8();
00585
00586 if (dstBeing) {
00587 dstBeing->setStunMode(stunMode);
00588 dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
00589 dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
00590 }
00591 break;
00592
00593 case SMSG_BEING_STATUS_CHANGE:
00594
00595 status = msg.readInt16();
00596 id = msg.readInt32();
00597 flag = msg.readInt8();
00598
00599 dstBeing = beingManager->findBeing(id);
00600 if (dstBeing)
00601 dstBeing->setStatusEffect(status, flag);
00602 break;
00603 }
00604 }
00605
00606 }