Mana
Loading...
Searching...
No Matches
beinghandler.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana 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
23
24#include "actorspritemanager.h"
25#include "being.h"
26#include "effectmanager.h"
27#include "localplayer.h"
28
29#include "gui/okdialog.h"
30
31#include "net/net.h"
32
37
38#include "playerrelations.h"
39#include "resources/abilitydb.h"
40#include "resources/emotedb.h"
41#include "resources/hairdb.h"
42
43#include "utils/gettext.h"
44
45#define POSITION_DIFF_TOLERANCE 48
46
47namespace ManaServ {
48
67
69{
70 switch (msg.getId())
71 {
74 break;
77 break;
80 break;
83 break;
86 break;
89 break;
92 break;
95 break;
98 break;
101 break;
104 break;
105 }
106}
107
108static void handleLooks(Being *being, MessageIn &msg)
109{
110 const int hairStyle = msg.readInt8();
111 const int hairColor = msg.readInt8();
112 being->setSprite(SPRITE_LAYER_HAIR, hairStyle * -1,
113 hairDB.getHairColor(hairColor));
114
115 std::map<unsigned, int> equippedSlots;
116
117 if (msg.getUnreadLength() > 1) {
118 int equippedSlotCount = msg.readInt8();
119 while (equippedSlotCount-- > 0) {
120 unsigned slot = msg.readInt8();
121 int itemId = msg.readInt16();
122 equippedSlots[slot] = itemId;
123 }
124 }
125
126 unsigned endSlot = equippedSlots.empty() ? 0 : equippedSlots.rbegin()->first + 1;
127 if (being->getSpriteCount() > endSlot + FIXED_SPRITE_LAYER_SIZE)
128 endSlot = being->getSpriteCount() - FIXED_SPRITE_LAYER_SIZE;
129
130 for (unsigned slot = 0; slot < endSlot; ++slot)
131 {
132 auto it = equippedSlots.find(slot);
133 if (it == equippedSlots.end())
134 {
135 being->setSprite(slot + FIXED_SPRITE_LAYER_SIZE, 0);
136 }
137 else
138 {
140 it->second,
141 std::string(),
143 }
144 }
145}
146
148{
149 const int type = msg.readInt8();
150 const int id = msg.readInt16();
151 const auto action = static_cast<Being::Action>(msg.readInt8());
152 const int px = msg.readInt16();
153 const int py = msg.readInt16();
154 const auto direction = static_cast<BeingDirection>(msg.readInt8());
155 const Gender gender = getGender(msg.readInt8());
156
157 Being *being;
158
159 switch (type)
160 {
161 case OBJECT_CHARACTER:
162 {
163 std::string name = msg.readString();
164 if (local_player->getName() == name)
165 {
166 being = local_player;
167 being->setId(id);
168 }
169 else
170 {
173 being->setName(name);
174 }
175
176 handleLooks(being, msg);
177 } break;
178
179 case OBJECT_MONSTER:
180 case OBJECT_NPC:
181 {
182 int subtype = msg.readInt16();
185 std::string name = msg.readString();
186 if (!name.empty())
187 being->setName(name);
188 } break;
189
190 default:
191 return;
192 }
193
194 being->setPosition(px, py);
195 being->setDestination(px, py);
196 being->setDirection(direction);
197 being->setAction(action);
198 being->setGender(gender);
199}
200
202{
204 if (!being)
205 return;
206
208}
209
211{
213 if (!being)
214 return;
215
217 {
218 const int fx = EmoteDB::get(msg.readInt8() - 1).effectId;
219 effectManager->trigger(fx, being);
220 }
221}
222
224{
225 while (msg.getUnreadLength())
226 {
227 const int id = msg.readInt16();
228 const int flags = msg.readInt8();
229
230 if (!(flags & (MOVING_POSITION | MOVING_DESTINATION)))
231 continue;
232
233 int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0;
234
235 if (flags & MOVING_POSITION)
236 {
237 sx = msg.readInt16();
238 sy = msg.readInt16();
239 }
240
241 if (flags & MOVING_DESTINATION)
242 {
243 dx = msg.readInt16();
244 dy = msg.readInt16();
245 speed = msg.readInt8();
246 }
247
248 Being *being = actorSpriteManager->findBeing(id);
249 if (!being)
250 continue;
251
252 if (speed)
253 {
254 /*
255 * The being's speed is transfered in tiles per second * 10
256 * to keep it transferable in a Byte.
257 * We set it back to tiles per second and in a float.
258 */
259 float speedTilesSeconds = (float) speed / 10;
260 being->setMoveSpeed(Vector(speedTilesSeconds, speedTilesSeconds,
261 0));
262 }
263
264 // Ignore messages from the server for the local player
265 if (being == local_player)
266 continue;
267
268 // If the position differs too much from the actual one, we resync
269 // the being position
270 if (flags & MOVING_POSITION)
271 {
272 Vector serverPos(sx, sy);
273 if (serverPos.length()
275 being->setPosition(serverPos);
276 }
277
278 if (flags & MOVING_DESTINATION)
279 being->setDestination(dx, dy);
280 }
281}
282
284{
286 if (!being)
287 return;
288
289 const int abilityId = msg.readInt8();
290 const int x = msg.readInt16();
291 const int y = msg.readInt16();
292
293 being->lookAt(Vector(x, y));
294
295 if (auto ability = AbilityDB::get(abilityId))
296 being->setAction(ability->useAction);
297}
298
300{
302 if (!being)
303 return;
304
305 const int abilityId = msg.readInt8();
306 const int targetId = msg.readInt16();
307
308 if (Being *target = actorSpriteManager->findBeing(targetId))
309 being->lookAt(target->getPosition());
310
311 if (auto ability = AbilityDB::get(abilityId))
312 being->setAction(ability->useAction);
313}
314
316{
318 if (!being)
319 return;
320
321 const int abilityId = msg.readInt8();
322 const int direction = msg.readInt8();
323
324 being->setDirection(direction);
325
326 if (auto ability = AbilityDB::get(abilityId))
327 being->setAction(ability->useAction);
328}
329
331{
332 while (msg.getUnreadLength())
333 {
335 int damage = msg.readInt16();
336 if (being)
337 being->takeDamage(nullptr, damage, Being::HIT);
338 }
339}
340
342{
344 auto action = (Being::Action) msg.readInt8();
345 if (!being)
346 return;
347
348 being->setAction(action);
349
350 if (action == Being::DEAD && being == local_player)
351 {
352 static char const *const deadMsg[] =
353 {
354 _("You are dead."),
355 _("We regret to inform you that your character was killed in "
356 "battle."),
357 _("You are not that alive anymore."),
358 _("The cold hands of the grim reaper are grabbing for your soul."),
359 _("Game Over!"),
360 _("No, kids. Your character did not really die. It... err... "
361 "went to a better place."),
362 _("Your plan of breaking your enemies weapon by bashing it with "
363 "your throat failed."),
364 _("I guess this did not run too well."),
365 _("Do you want your possessions identified?"), // Nethack reference
366 _("Sadly, no trace of you was ever found..."), // Secret of Mana reference
367 _("Annihilated."), // Final Fantasy VI reference
368 _("Looks like you got your head handed to you."), // Earthbound reference
369 _("You screwed up again, dump your body down the tubes and get "
370 "you another one.") // Leisure Suit Larry 1 Reference
371
372 };
373 std::string message(deadMsg[rand()%13]);
374 message.append(std::string(" ") + _("Press OK to respawn."));
375 auto *dlg = new OkDialog(_("You Died"), message, false);
376 dlg->addActionListener(&(ManaServ::respawnListener));
377 }
378}
379
381{
383 if (!being || being->getType() != ActorSprite::PLAYER)
384 return;
385
386 handleLooks(being, msg);
387}
388
390{
392 if (!being)
393 return;
394 int data = msg.readInt8();
395
396 // The direction for the player's character is handled on client side.
397 if (being != local_player)
398 being->setDirection((BeingDirection) data);
399}
400
401} // namespace ManaServ
ActorSpriteManager * actorSpriteManager
Definition game.cpp:110
Gender
Definition being.h:58
Being * createBeing(int id, ActorSprite::Type type, int subtype)
Create a Being and add it to the list of ActorSprites.
void destroyActor(ActorSprite *actor)
Immediately destroys the given actor.
Being * findBeing(int id) const
Returns a specific Being, by id;.
void setId(int id)
Definition actorsprite.h:66
const Vector & getPosition() const
Returns the pixel position of this actor.
Definition actor.h:53
Definition being.h:65
void setPosition(const Vector &pos) final
Sets the pixel position of this actor.
Definition being.cpp:187
unsigned getSpriteCount() const
Definition being.h:277
@ HIT
Definition being.h:92
void setSprite(unsigned slot, int id, const std::string &color=std::string(), bool isWeapon=false)
Sets visible equipments for this being.
Definition being.cpp:1254
void setDestination(int ex, int ey)
Creates a path for the being from current position to ex and ey.
Definition being.cpp:197
void setMoveSpeed(const Vector &speed)
Sets the move speed.
Definition being.cpp:173
void setDirection(uint8_t direction)
Sets the current direction.
Definition being.cpp:782
Type getType() const final
Returns the type of the ActorSprite.
Definition being.h:122
void lookAt(const Vector &destVec)
Make the being look at a given pixel position.
Definition being.cpp:702
void setName(const std::string &name)
Sets the name for the being.
Definition being.cpp:463
Action
Action the being is currently performing WARNING: Has to be in sync with the same enum in the Being c...
Definition being.h:73
@ DEAD
Definition being.h:78
virtual void setAction(Action action, int attackId=1)
Sets the current action.
Definition being.cpp:624
const std::string & getName() const
Returns the name of the being.
Definition being.h:190
void setGender(Gender gender)
Sets the gender of this being.
Definition being.cpp:1313
void takeDamage(Being *attacker, int damage, AttackType type, int attackId=1)
Puts a damage bubble above this being.
Definition being.cpp:316
bool trigger(int id, Being *being, int rotation=0)
Triggers a effect with the id, at the specified being, and with the given rotation in degree: 0° = Do...
const std::string & getHairColor(int id) const
Definition hairdb.cpp:79
void handleBeingAbilityBeingMessage(MessageIn &msg)
void handleBeingEnterMessage(MessageIn &msg)
void handleBeingsDamageMessage(MessageIn &msg)
void handleBeingAbilityPointMessage(MessageIn &msg)
void handleBeingActionChangeMessage(MessageIn &msg)
void handleBeingEmoteMessage(MessageIn &msg)
void handleBeingLooksChangeMessage(MessageIn &msg)
void handleMessage(MessageIn &msg) override
void handleBeingLeaveMessage(MessageIn &msg)
void handleBeingsMoveMessage(MessageIn &msg)
void handleBeingAbilityDirectionMessage(MessageIn &msg)
void handleBeingDirChangeMessage(MessageIn &msg)
bool isWeaponSlot(unsigned int slotTypeId) const override
Used for parsing an incoming message from manaserv.
Definition messagein.h:37
uint16_t readInt16()
Reads an unsigned 16-bit integer from the message.
Definition messagein.cpp:58
unsigned int getUnreadLength() const
Returns the length of unread data.
Definition messagein.h:54
std::string readString(int length=-1)
Reads a string.
Definition messagein.cpp:92
uint16_t getId() const
Returns the message ID.
Definition messagein.h:44
uint8_t readInt8()
Reads an unsigned 8-bit integer from the message.
Definition messagein.cpp:43
const uint16_t * handledMessages
An 'Ok' button dialog.
Definition okdialog.h:34
bool hasPermission(Being *being, unsigned int flags)
Tests whether the player in question is being ignored for any of the actions in the specified flags.
Vector class.
Definition vector.h:33
float length() const
Returns the length of this vector.
Definition vector.h:140
HairDB hairDB
Hair styles and colors info database.
Definition client.cpp:107
EffectManager * effectManager
Definition game.cpp:114
#define _(s)
Definition gettext.h:38
LocalPlayer * local_player
#define POSITION_DIFF_TOLERANCE
AbilityInfo * get(int id)
Gets the ability info for ID.
Definition abilitydb.cpp:89
const Emote & get(int id)
Definition emotedb.cpp:115
@ SPRITE_LAYER_HAIR
@ FIXED_SPRITE_LAYER_SIZE
BeingDirection
Beings and actors directions WARNING: Has to be in sync with the same enum in the Being class of the ...
Gender getGender(int gender)
Helper function for getting gender by int.
@ GPMSG_BEING_ABILITY_DIRECTION
InventoryHandler * getInventoryHandler()
Definition net.cpp:90
PlayerRelationsManager player_relations
int effectId
Definition emotedb.h:34