diff options
author | David Athay <ko2fan@gmail.com> | 2009-02-11 09:30:26 +0000 |
---|---|---|
committer | David Athay <ko2fan@gmail.com> | 2009-02-11 09:30:26 +0000 |
commit | 91111ca5d13072ea3b834e23835df9c077329e39 (patch) | |
tree | f0af8dd08b766164835cf9b5412a9aa3267dbad7 /src/being.cpp | |
parent | 8046bb2626b30fecdcea54eb0aa3349cdb7d277b (diff) | |
parent | 63ac001daa7dfc0735dfefd9c2829c8786b4edaf (diff) | |
download | mana-91111ca5d13072ea3b834e23835df9c077329e39.tar.gz mana-91111ca5d13072ea3b834e23835df9c077329e39.tar.bz2 mana-91111ca5d13072ea3b834e23835df9c077329e39.tar.xz mana-91111ca5d13072ea3b834e23835df9c077329e39.zip |
Merge branch 'master' of git@gitorious.org:tmw/eathena
Diffstat (limited to 'src/being.cpp')
-rw-r--r-- | src/being.cpp | 268 |
1 files changed, 202 insertions, 66 deletions
diff --git a/src/being.cpp b/src/being.cpp index 7036b8cd..0ccf675c 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -22,52 +22,68 @@ #include "being.h" #include "animatedsprite.h" -#include "equipment.h" +#include "configuration.h" +#include "effectmanager.h" #include "game.h" #include "graphics.h" +#include "localplayer.h" #include "log.h" #include "map.h" #include "particle.h" #include "sound.h" -#include "localplayer.h" #include "text.h" #include "statuseffect.h" -#include "resources/itemdb.h" -#include "resources/resourcemanager.h" +#include "gui/speechbubble.h" + +#include "resources/colordb.h" + +#include "resources/emotedb.h" +#include "resources/image.h" #include "resources/imageset.h" +#include "resources/itemdb.h" #include "resources/iteminfo.h" +#include "resources/resourcemanager.h" #include "gui/gui.h" +#include "gui/speechbubble.h" #include "utils/dtor.h" +#include "utils/gettext.h" #include "utils/tostring.h" - +#include "utils/trim.h" #include "utils/xml.h" #include <cassert> +#include <cmath> #define BEING_EFFECTS_FILE "effects.xml" #define HAIR_FILE "hair.xml" int Being::instances = 0; -ImageSet *Being::emotionSet = NULL; +int Being::mNumberOfHairstyles = 1; +std::vector<AnimatedSprite*> Being::emotionSet; static const int X_SPEECH_OFFSET = 18; static const int Y_SPEECH_OFFSET = 60; +static const int DEFAULT_WIDTH = 32; +static const int DEFAULT_HEIGHT = 32; + Being::Being(int id, int job, Map *map): mJob(job), mX(0), mY(0), - mAction(0), + mAction(STAND), mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), - mEquipment(new Equipment()), mId(id), mWalkSpeed(150), mDirection(DOWN), mMap(NULL), + mName(""), + mIsGM(false), + mParticleEffects(config.getValue("particleeffects", 1)), mEquippedWeapon(NULL), mHairStyle(1), mHairColor(0), mGender(GENDER_UNSPECIFIED), @@ -83,16 +99,33 @@ Being::Being(int id, int job, Map *map): { setMap(map); + mSpeechBubble = new SpeechBubble(); + if (instances == 0) { - // Load the emotion set - ResourceManager *rm = ResourceManager::getInstance(); - emotionSet = rm->getImageSet("graphics/gui/emotions.png", 30, 32); - if (!emotionSet) logger->error("Unable to load emotions!"); + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + EmoteInfo info = EmoteDB::get(i); + + std::string file = "graphics/sprites/" + info.sprites.front()->sprite; + int variant = info.sprites.front()->variant; + emotionSet.push_back(AnimatedSprite::load(file, variant)); + } + + // Hairstyles are encoded as negative numbers. Count how far negative we can go. + int hairstyles = 1; + while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != "error.xml") + { + hairstyles++; + } + mNumberOfHairstyles = hairstyles; } instances++; - mSpeech = 0; + mSpeech = ""; + mNameColor = 0x202020; + mText = 0; } Being::~Being() @@ -106,11 +139,11 @@ Being::~Being() if (instances == 0) { - emotionSet->decRef(); - emotionSet = NULL; + delete_all(emotionSet); } - delete mSpeech; + delete mSpeechBubble; + delete mText; } void Being::setDestination(Uint16 destX, Uint16 destY) @@ -139,8 +172,8 @@ void Being::setPath(const Path &path) void Being::setHairStyle(int style, int color) { - mHairStyle = style < 0 ? mHairStyle : style % getHairStylesNr(); - mHairColor = color < 0 ? mHairColor : color % getHairColorsNr(); + mHairStyle = style < 0 ? mHairStyle : style % mNumberOfHairstyles; + mHairColor = color < 0 ? mHairColor : color % ColorDB::size(); } void Being::setSprite(int slot, int id, std::string color) @@ -152,13 +185,44 @@ void Being::setSprite(int slot, int id, std::string color) void Being::setSpeech(const std::string &text, Uint32 time) { - // don't introduce a memory leak - delete mSpeech; + mSpeech = text; + + // Trim whitespace + trim(mSpeech); + + // check for links + std::string::size_type start = mSpeech.find('['); + std::string::size_type end = mSpeech.find(']', start); + + while (start != std::string::npos && end != std::string::npos) + { + // Catch multiple embeds and ignore them so it doesn't crash the client. + while ((mSpeech.find('[', start + 1) != std::string::npos) && + (mSpeech.find('[', start + 1) < end)) + { + start = mSpeech.find('[', start + 1); + } - mSpeech = new Text(text, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET, - gcn::Graphics::CENTER, - gcn::Color(255, 255, 255), true); - mSpeechTime = 500; + std::string::size_type position = mSpeech.find('|'); + if (mSpeech[start + 1] == '@' && mSpeech[start + 2] == '@') + { + mSpeech.erase(end, 1); + mSpeech.erase(start, (position - start) + 1); + } + position = mSpeech.find('@'); + + while (position != std::string::npos) + { + mSpeech.erase(position, 2); + position = mSpeech.find('@'); + } + + start = mSpeech.find('[', start + 1); + end = mSpeech.find(']', start); + } + + if (!mSpeech.empty()) + mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME; } void Being::takeDamage(int amount) @@ -173,10 +237,6 @@ void Being::takeDamage(int amount) } else { - // Hit particle effect - controlParticle(particleEngine->addEffect( - "graphics/particles/hit.particle.xml", 0, 0)); - if (getType() == MONSTER) { font = hitBlueFont; @@ -192,6 +252,26 @@ void Being::takeDamage(int amount) mPx + 16, mPy + 16); } +void Being::showCrit() +{ + gcn::Font *font; + std::string text = "crit!"; + + // Selecting the right color + if (getType() == MONSTER) + { + font = hitBlueFont; + } + else + { + font = hitRedFont; + } + + // Show crit notice + particleEngine->addTextSplashEffect(text, 255, 255, 255, font, + mPx + 16, mPy + 16); +} + void Being::handleAttack(Being *victim, int damage) { setAction(Being::ATTACK); @@ -225,9 +305,10 @@ void Being::controlParticle(Particle *particle) mChildParticleEffects.addLocally(particle); } -void Being::setAction(Uint8 action) +void Being::setAction(Action action) { SpriteAction currentAction = ACTION_INVALID; + switch (action) { case WALK: @@ -241,7 +322,8 @@ void Being::setAction(Uint8 action) { currentAction = mEquippedWeapon->getAttackType(); } - else { + else + { currentAction = ACTION_ATTACK; } for (int i = 0; i < VECTOREND_SPRITE; i++) @@ -278,16 +360,18 @@ void Being::setAction(Uint8 action) } } - void Being::setDirection(Uint8 direction) { + if (mDirection == direction) + return; + mDirection = direction; SpriteDirection dir = getSpriteDirection(); for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) - mSprites[i]->setDirection(dir); + if (mSprites[i]) + mSprites[i]->setDirection(dir); } } @@ -307,8 +391,9 @@ SpriteDirection Being::getSpriteDirection() const { dir = DIRECTION_RIGHT; } - else { - dir = DIRECTION_LEFT; + else + { + dir = DIRECTION_LEFT; } return dir; @@ -352,28 +437,28 @@ void Being::nextStep() void Being::logic() { // Reduce the time that speech is still displayed - if (mSpeechTime > 0 && mSpeech) + if (mSpeechTime > 0) + mSpeechTime--; + + // Remove text if speech boxes aren't being used + if (mSpeechTime == 0 && mText) { - if (--mSpeechTime == 0) - { - delete mSpeech; - mSpeech = 0; - } + delete mText; + mText = 0; } int oldPx = mPx; int oldPy = mPy; + // Update pixel coordinates mPx = mX * 32 + getXOffset(); mPy = mY * 32 + getYOffset(); + if (mPx != oldPx || mPy != oldPy) { - if (mSpeech) - { - mSpeech->adviseXY(mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET); - } updateCoords(); } + if (mEmotion != 0) { mEmotionTime--; @@ -385,7 +470,7 @@ void Being::logic() // Update sprite animations for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) + if (mSprites[i]) { mSprites[i]->update(tick_time * 10); } @@ -415,7 +500,7 @@ void Being::draw(Graphics *graphics, int offsetX, int offsetY) const for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) + if (mSprites[i]) { mSprites[i]->draw(graphics, px, py); } @@ -431,8 +516,47 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY) const int py = mPy + offsetY - 60; const int emotionIndex = mEmotion - 1; - if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size()) - graphics->drawImage(emotionSet->get(emotionIndex), px, py); + if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast()) + emotionSet[emotionIndex]->draw(graphics, px, py); +} + +void Being::drawSpeech(int offsetX, int offsetY) +{ + int px = mPx + offsetX; + int py = mPy + offsetY; + + // Draw speech above this being + if (mSpeechTime > 0 && config.getValue("speechbubble", 1)) + { + if (mText) + { + delete mText; + mText = 0; + } + + mSpeechBubble->setCaption(mName, mNameColor); + + // Not quite centered, but close enough. However, it's not too important to get + // it right right now, as it doesn't take bubble collision into account yet. + mSpeechBubble->setText(mSpeech); + mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), py - 70 - + (mSpeechBubble->getNumRows()*14)); + mSpeechBubble->setVisible(true); + } + else if (mSpeechTime > 0 && !config.getValue("speechbubble", 1)) + { + mSpeechBubble->setVisible(false); + // don't introduce a memory leak + if (mText) + delete mText; + + mText = new Text(mSpeech, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET, + gcn::Graphics::CENTER, gcn::Color(255, 255, 255)); + } + else if (mSpeechTime == 0) + { + mSpeechBubble->setVisible(false); + } } Being::Type Being::getType() const @@ -455,9 +579,11 @@ void Being::handleStatusEffect(StatusEffect *effect, int effectId) if (!effect) return; - SpriteAction action = effect->getAction(); - if (action != ACTION_INVALID) - setAction(action); + // TODO: Find out how this is meant to be used + // (SpriteAction != Being::Action) + //SpriteAction action = effect->getAction(); + //if (action != ACTION_INVALID) + // setAction(action); Particle *particle = effect->getParticle(); @@ -497,7 +623,8 @@ void Being::setStatusEffect(int index, bool active) int Being::getOffset(char pos, char neg) const { // Check whether we're walking in the requested direction - if (mAction != WALK || !(mDirection & (pos | neg))) { + if (mAction != WALK || !(mDirection & (pos | neg))) + { return 0; } @@ -505,27 +632,32 @@ int Being::getOffset(char pos, char neg) const // We calculate the offset _from_ the _target_ location offset -= 32; - if (offset > 0) { + if (offset > 0) + { offset = 0; } // Going into negative direction? Invert the offset. - if (mDirection & pos) { + if (mDirection & pos) + { offset = -offset; } return offset; } - int Being::getWidth() const { if (mSprites[BASE_SPRITE]) { - return mSprites[BASE_SPRITE]->getWidth(); + const int width = mSprites[BASE_SPRITE]->getWidth() > DEFAULT_WIDTH ? + mSprites[BASE_SPRITE]->getWidth() : + DEFAULT_WIDTH; + return width; } - else { - return 0; + else + { + return DEFAULT_WIDTH; } } @@ -534,10 +666,14 @@ int Being::getHeight() const { if (mSprites[BASE_SPRITE]) { - return mSprites[BASE_SPRITE]->getHeight(); + const int height = mSprites[BASE_SPRITE]->getHeight() > DEFAULT_HEIGHT ? + mSprites[BASE_SPRITE]->getHeight() : + DEFAULT_HEIGHT; + return height; } - else { - return 0; + else + { + return DEFAULT_HEIGHT; } } @@ -620,14 +756,14 @@ void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx) return; } - if (gfx && ed->mGFXEffect != "") { + if (gfx && !ed->mGFXEffect.empty()) { Particle *selfFX; selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0); controlParticle(selfFX); } - if (sfx && ed->mSFXEffect != "") { + if (sfx && !ed->mSFXEffect.empty()) { sound.playSfx(ed->mSFXEffect); } } @@ -695,7 +831,7 @@ static void initializeHair() int index = atoi(XML::getProperty(node, "id", "-1").c_str()); std::string value = XML::getProperty(node, "value", ""); - if (index >= 0 && value != "") { + if (index >= 0 && !value.empty()) { if (index >= hairColorsNr) { hairColorsNr = index + 1; hairColors.resize(hairColorsNr, "#000000"); @@ -706,7 +842,7 @@ static void initializeHair() } } // done initializing - if (hairColorsNr == 0) { // No colours -> black only + if (hairColorsNr == 0) { // No colors -> black only hairColorsNr = 1; hairColors.resize(hairColorsNr, "#000000"); } |