summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2009-03-25 22:50:59 +0100
committerBjørn Lindeijer <bjorn@lindeijer.nl>2009-03-25 22:50:59 +0100
commitcc79f0fe21e1a2ef73cbe987d54e848b9a47142d (patch)
treeedd316eb6094f0c02d6d014385865dcd88a2bc56 /src
parentb0df784f1be44a657ca8092069488602270629b7 (diff)
parent99e8a3fd77b63a029fe02dcf771b6af1aad252ed (diff)
downloadmana-cc79f0fe21e1a2ef73cbe987d54e848b9a47142d.tar.gz
mana-cc79f0fe21e1a2ef73cbe987d54e848b9a47142d.tar.bz2
mana-cc79f0fe21e1a2ef73cbe987d54e848b9a47142d.tar.xz
mana-cc79f0fe21e1a2ef73cbe987d54e848b9a47142d.zip
Merge branch 'eathena/master'
Conflicts: A lot of files.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt21
-rw-r--r--src/Makefile.am15
-rw-r--r--src/being.cpp230
-rw-r--r--src/being.h76
-rw-r--r--src/beingmanager.cpp54
-rw-r--r--src/beingmanager.h44
-rw-r--r--src/engine.cpp2
-rw-r--r--src/floor_item.cpp10
-rw-r--r--src/floor_item.h20
-rw-r--r--src/flooritemmanager.cpp9
-rw-r--r--src/flooritemmanager.h7
-rw-r--r--src/game.cpp184
-rw-r--r--src/game.h2
-rw-r--r--src/graphics.cpp60
-rw-r--r--src/graphics.h13
-rw-r--r--src/gui/browserbox.cpp25
-rw-r--r--src/gui/button.cpp13
-rw-r--r--src/gui/buy.cpp81
-rw-r--r--src/gui/buy.h17
-rw-r--r--src/gui/buysell.cpp62
-rw-r--r--src/gui/buysell.h16
-rw-r--r--src/gui/char_select.cpp35
-rw-r--r--src/gui/char_server.cpp2
-rw-r--r--src/gui/chat.cpp85
-rw-r--r--src/gui/chat.h26
-rw-r--r--src/gui/checkbox.cpp13
-rw-r--r--src/gui/checkbox.h5
-rw-r--r--src/gui/color.cpp146
-rw-r--r--src/gui/color.h136
-rw-r--r--src/gui/confirm_dialog.cpp20
-rw-r--r--src/gui/connection.cpp7
-rw-r--r--src/gui/debugwindow.cpp49
-rw-r--r--src/gui/debugwindow.h2
-rw-r--r--src/gui/emotecontainer.cpp7
-rw-r--r--src/gui/emotecontainer.h2
-rw-r--r--src/gui/emoteshortcutcontainer.cpp41
-rw-r--r--src/gui/emoteshortcutcontainer.h2
-rw-r--r--src/gui/emotewindow.cpp2
-rw-r--r--src/gui/equipmentwindow.cpp45
-rw-r--r--src/gui/gui.cpp37
-rw-r--r--src/gui/gui.h20
-rw-r--r--src/gui/help.cpp13
-rw-r--r--src/gui/inventorywindow.cpp13
-rw-r--r--src/gui/inventorywindow.h10
-rw-r--r--src/gui/item_amount.cpp122
-rw-r--r--src/gui/item_amount.h13
-rw-r--r--src/gui/itemcontainer.cpp19
-rw-r--r--src/gui/itemlinkhandler.cpp17
-rw-r--r--src/gui/itempopup.cpp66
-rw-r--r--src/gui/itempopup.h33
-rw-r--r--src/gui/itemshortcutcontainer.cpp84
-rw-r--r--src/gui/itemshortcutcontainer.h5
-rw-r--r--src/gui/label.cpp40
-rw-r--r--src/gui/label.h55
-rw-r--r--src/gui/listbox.cpp103
-rw-r--r--src/gui/listbox.h19
-rw-r--r--src/gui/login.cpp45
-rw-r--r--src/gui/menuwindow.cpp14
-rw-r--r--src/gui/menuwindow.h4
-rw-r--r--src/gui/minimap.cpp16
-rw-r--r--src/gui/ministatus.cpp52
-rw-r--r--src/gui/ministatus.h4
-rw-r--r--src/gui/npc_text.cpp62
-rw-r--r--src/gui/npc_text.h33
-rw-r--r--src/gui/npcintegerdialog.cpp60
-rw-r--r--src/gui/npcintegerdialog.h19
-rw-r--r--src/gui/npclistdialog.cpp64
-rw-r--r--src/gui/npclistdialog.h21
-rw-r--r--src/gui/npcstringdialog.cpp48
-rw-r--r--src/gui/npcstringdialog.h15
-rw-r--r--src/gui/ok_dialog.cpp19
-rw-r--r--src/gui/palette.cpp347
-rw-r--r--src/gui/palette.h350
-rw-r--r--src/gui/playerbox.cpp3
-rw-r--r--src/gui/popup.cpp209
-rw-r--r--src/gui/popup.h194
-rw-r--r--src/gui/popupmenu.cpp12
-rw-r--r--src/gui/popupmenu.h4
-rw-r--r--src/gui/progressbar.cpp26
-rw-r--r--src/gui/progressbar.h3
-rw-r--r--src/gui/radiobutton.cpp3
-rw-r--r--src/gui/recorder.cpp8
-rw-r--r--src/gui/register.cpp18
-rw-r--r--src/gui/register.h3
-rw-r--r--src/gui/scrollarea.cpp6
-rw-r--r--src/gui/sell.cpp123
-rw-r--r--src/gui/sell.h17
-rw-r--r--src/gui/setup.cpp55
-rw-r--r--src/gui/setup.h8
-rw-r--r--src/gui/setup_audio.cpp10
-rw-r--r--src/gui/setup_colors.cpp268
-rw-r--r--src/gui/setup_colors.h10
-rw-r--r--src/gui/setup_joystick.cpp5
-rw-r--r--src/gui/setup_players.cpp13
-rw-r--r--src/gui/setup_video.cpp100
-rw-r--r--src/gui/setup_video.h6
-rw-r--r--src/gui/shop.cpp48
-rw-r--r--src/gui/shop.h49
-rw-r--r--src/gui/shoplistbox.cpp51
-rw-r--r--src/gui/shoplistbox.h2
-rw-r--r--src/gui/shortcutcontainer.cpp29
-rw-r--r--src/gui/shortcutwindow.cpp31
-rw-r--r--src/gui/shortcutwindow.h5
-rw-r--r--src/gui/skill.cpp17
-rw-r--r--src/gui/skin.cpp191
-rw-r--r--src/gui/skin.h101
-rw-r--r--src/gui/slider.cpp10
-rw-r--r--src/gui/speechbubble.cpp31
-rw-r--r--src/gui/speechbubble.h29
-rw-r--r--src/gui/status.cpp189
-rw-r--r--src/gui/status.h5
-rw-r--r--src/gui/statuswindow.cpp50
-rw-r--r--src/gui/statuswindow.h2
-rw-r--r--src/gui/storagewindow.cpp210
-rw-r--r--src/gui/storagewindow.h110
-rw-r--r--src/gui/table.cpp56
-rw-r--r--src/gui/textbox.cpp37
-rw-r--r--src/gui/textbox.h15
-rw-r--r--src/gui/textfield.cpp35
-rw-r--r--src/gui/textrenderer.h81
-rw-r--r--src/gui/trade.cpp87
-rw-r--r--src/gui/trade.h12
-rw-r--r--src/gui/truetypefont.cpp3
-rw-r--r--src/gui/truetypefont.h6
-rw-r--r--src/gui/updatewindow.cpp8
-rw-r--r--src/gui/viewport.cpp59
-rw-r--r--src/gui/viewport.h29
-rw-r--r--src/gui/widgets/dropdown.cpp46
-rw-r--r--src/gui/widgets/tab.cpp18
-rw-r--r--src/gui/widgets/tabbedarea.cpp17
-rw-r--r--src/gui/widgets/textpreview.cpp81
-rw-r--r--src/gui/widgets/textpreview.h142
-rw-r--r--src/gui/window.cpp444
-rw-r--r--src/gui/window.h67
-rw-r--r--src/gui/windowcontainer.cpp2
-rw-r--r--src/gui/windowcontainer.h7
-rw-r--r--src/inventory.cpp16
-rw-r--r--src/inventory.h15
-rw-r--r--src/keyboardconfig.cpp1
-rw-r--r--src/localplayer.cpp122
-rw-r--r--src/localplayer.h28
-rw-r--r--src/main.cpp103
-rw-r--r--src/map.cpp14
-rw-r--r--src/monster.cpp17
-rw-r--r--src/monster.h15
-rw-r--r--src/net/ea/beinghandler.cpp40
-rw-r--r--src/net/ea/buysellhandler.cpp40
-rw-r--r--src/net/ea/chathandler.cpp2
-rw-r--r--src/net/ea/equipmenthandler.cpp6
-rw-r--r--src/net/ea/inventoryhandler.cpp105
-rw-r--r--src/net/ea/npchandler.cpp43
-rw-r--r--src/net/ea/playerhandler.cpp45
-rw-r--r--src/net/ea/protocol.h18
-rw-r--r--src/net/ea/skillhandler.cpp8
-rw-r--r--src/net/ea/tradehandler.cpp6
-rw-r--r--src/net/tmwserv/beinghandler.cpp2
-rw-r--r--src/net/tmwserv/buysellhandler.cpp2
-rw-r--r--src/net/tmwserv/npchandler.cpp2
-rw-r--r--src/net/tmwserv/playerhandler.cpp2
-rw-r--r--src/npc.cpp108
-rw-r--r--src/npc.h18
-rw-r--r--src/openglgraphics.cpp117
-rw-r--r--src/openglgraphics.h4
-rw-r--r--src/particle.cpp53
-rw-r--r--src/particle.h11
-rw-r--r--src/player.cpp37
-rw-r--r--src/player_relations.cpp33
-rw-r--r--src/player_relations.h5
-rw-r--r--src/resources/dye.cpp14
-rw-r--r--src/resources/dye.h6
-rw-r--r--src/resources/emotedb.cpp24
-rw-r--r--src/resources/emotedb.h9
-rw-r--r--src/resources/image.cpp79
-rw-r--r--src/resources/image.h10
-rw-r--r--src/resources/itemdb.cpp11
-rw-r--r--src/resources/iteminfo.h26
-rw-r--r--src/shopitem.cpp58
-rw-r--r--src/shopitem.h90
-rw-r--r--src/statuseffect.cpp28
-rw-r--r--src/statuseffect.h4
-rw-r--r--src/text.cpp42
-rw-r--r--src/text.h6
-rw-r--r--src/textparticle.cpp18
-rw-r--r--src/textparticle.h7
-rw-r--r--src/units.cpp4
185 files changed, 5836 insertions, 2582 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 94688e66..babf1629 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -67,10 +67,10 @@ SET(SRCS
gui/widgets/tab.h
gui/widgets/tabbedarea.cpp
gui/widgets/tabbedarea.h
+ gui/widgets/textpreview.cpp
+ gui/widgets/textpreview.h
gui/browserbox.cpp
gui/browserbox.h
- gui/buddywindow.cpp
- gui/buddywindow.h
gui/button.cpp
gui/button.h
gui/buy.cpp
@@ -91,8 +91,6 @@ SET(SRCS
gui/chatinput.h
gui/checkbox.cpp
gui/checkbox.h
- gui/color.cpp
- gui/color.h
gui/confirm_dialog.cpp
gui/confirm_dialog.h
gui/connection.cpp
@@ -132,9 +130,11 @@ SET(SRCS
gui/itempopup.cpp
gui/itempopup.h
gui/itemshortcutcontainer.cpp
- gui/itemshortcutcontainer.h\
+ gui/itemshortcutcontainer.h
gui/item_amount.cpp
gui/item_amount.h
+ gui/label.cpp
+ gui/label.h
gui/linkhandler.h
gui/listbox.cpp
gui/listbox.h
@@ -160,12 +160,16 @@ SET(SRCS
gui/npc_text.h
gui/ok_dialog.cpp
gui/ok_dialog.h
+ gui/palette.cpp
+ gui/palette.h
gui/partywindow.h
gui/partywindow.cpp
gui/passwordfield.cpp
gui/passwordfield.h
gui/playerbox.cpp
gui/playerbox.h
+ gui/popup.cpp
+ gui/popup.h
gui/popupmenu.cpp
gui/popupmenu.h
gui/progressbar.cpp
@@ -211,12 +215,16 @@ SET(SRCS
gui/shortcutcontainer.h
gui/skill.cpp
gui/skill.h
+ gui/skin.cpp
+ gui/skin.h
gui/slider.cpp
gui/slider.h
gui/speechbubble.cpp
gui/speechbubble.h
gui/status.cpp
gui/status.h
+ gui/storagewindow.cpp
+ gui/storagewindow.h
gui/table.cpp
gui/table.h
gui/table_model.cpp
@@ -227,6 +235,7 @@ SET(SRCS
gui/textdialog.h
gui/textfield.cpp
gui/textfield.h
+ gui/textrenderer.h
gui/trade.cpp
gui/trade.h
gui/truetypefont.cpp
@@ -461,6 +470,8 @@ SET(SRCS
textparticle.cpp
textparticle.h
tileset.h
+ units.cpp
+ units.h
vector.cpp
vector.h
effectmanager.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index dc03e66a..cafe46a7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,6 +19,8 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/widgets/tab.h \
gui/widgets/tabbedarea.cpp \
gui/widgets/tabbedarea.h \
+ gui/widgets/textpreview.cpp \
+ gui/widgets/textpreview.h \
gui/browserbox.cpp \
gui/browserbox.h \
gui/button.cpp \
@@ -35,8 +37,6 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/chatinput.h \
gui/checkbox.cpp \
gui/checkbox.h \
- gui/color.cpp \
- gui/color.h \
gui/confirm_dialog.cpp \
gui/confirm_dialog.h \
gui/debugwindow.cpp \
@@ -73,6 +73,8 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/itemshortcutcontainer.h \
gui/item_amount.cpp \
gui/item_amount.h \
+ gui/label.cpp \
+ gui/label.h \
gui/linkhandler.h \
gui/listbox.cpp \
gui/listbox.h \
@@ -94,10 +96,14 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/npc_text.h \
gui/ok_dialog.cpp \
gui/ok_dialog.h \
+ gui/palette.cpp \
+ gui/palette.h \
gui/passwordfield.cpp \
gui/passwordfield.h \
gui/playerbox.cpp \
gui/playerbox.h \
+ gui/popup.cpp \
+ gui/popup.h \
gui/popupmenu.cpp \
gui/popupmenu.h \
gui/progressbar.cpp \
@@ -137,6 +143,8 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/shortcutwindow.h \
gui/shortcutcontainer.cpp \
gui/shortcutcontainer.h \
+ gui/skin.cpp \
+ gui/skin.h \
gui/slider.cpp \
gui/slider.h \
gui/speechbubble.cpp \
@@ -151,6 +159,7 @@ tmw_SOURCES = gui/widgets/avatar.cpp \
gui/textdialog.h \
gui/textfield.cpp \
gui/textfield.h \
+ gui/textrenderer.h \
gui/trade.cpp \
gui/trade.h \
gui/truetypefont.cpp \
@@ -424,6 +433,8 @@ tmw_SOURCES += \
gui/skill.h \
gui/status.cpp \
gui/status.h \
+ gui/storagewindow.cpp \
+ gui/storagewindow.h \
net/ea/beinghandler.cpp \
net/ea/beinghandler.h \
net/ea/buysellhandler.cpp \
diff --git a/src/being.cpp b/src/being.cpp
index 7f5a7d33..c0623255 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -45,6 +45,7 @@
#include "resources/resourcemanager.h"
#include "gui/gui.h"
+#include "gui/palette.h"
#include "gui/speechbubble.h"
#include "utils/dtor.h"
@@ -63,9 +64,9 @@ const bool debug_movement = true;
#define BEING_EFFECTS_FILE "effects.xml"
#define HAIR_FILE "hair.xml"
-int Being::instances = 0;
+int Being::mNumberOfHairColors = 1;
int Being::mNumberOfHairstyles = 1;
-std::vector<AnimatedSprite*> Being::emotionSet;
+std::vector<std::string> Being::hairColors;
static const int X_SPEECH_OFFSET = 18;
static const int Y_SPEECH_OFFSET = 60;
@@ -79,6 +80,7 @@ Being::Being(int id, int job, Map *map):
mWalkTime(0),
#endif
mEmotion(0), mEmotionTime(0),
+ mSpeechTime(0),
mAttackSpeed(350),
mAction(STAND),
mJob(job),
@@ -99,7 +101,6 @@ Being::Being(int id, int job, Map *map):
#endif
mHairColor(0),
mGender(GENDER_UNSPECIFIED),
- mSpeechTime(0),
mPx(0), mPy(0),
mStunMode(0),
mSprites(VECTOREND_SPRITE, NULL),
@@ -119,31 +120,8 @@ Being::Being(int id, int job, Map *map):
mSpeechBubble = new SpeechBubble;
- if (instances == 0)
- {
- // 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 = "";
- mNameColor = 0x202020;
+ mNameColor = &guiPalette->getColor(Palette::CHAT);
mText = 0;
}
@@ -158,13 +136,6 @@ Being::~Being()
setMap(NULL);
- instances--;
-
- if (instances == 0)
- {
- delete_all(emotionSet);
- }
-
delete mSpeechBubble;
delete mText;
}
@@ -383,7 +354,7 @@ void Being::setSprite(int slot, int id, const std::string &color)
mSpriteColors[slot] = color;
}
-void Being::setSpeech(const std::string &text, Uint32 time)
+void Being::setSpeech(const std::string &text, int time)
{
mSpeech = text;
@@ -425,43 +396,69 @@ void Being::setSpeech(const std::string &text, Uint32 time)
mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME;
}
-void Being::takeDamage(int amount)
+void Being::takeDamage(Being *attacker, int amount, AttackType type)
{
gcn::Font *font;
- std::string damage = amount ? toString(amount) : "miss";
+ std::string damage = amount ? toString(amount) : type == FLEE ?
+ "dodge" : "miss";
+ const gcn::Color* color;
+
+ font = gui->getInfoParticleFont();
// Selecting the right color
- if (damage == "miss")
- font = hitYellowFont;
- else
+ if (type == CRITICAL || type == FLEE)
{
- if (getType() == MONSTER)
- font = hitBlueFont;
+ color = &guiPalette->getColor(Palette::HIT_CRITICAL);
+ }
+ else if (!amount)
+ {
+ if (attacker == player_node)
+ {
+ // This is intended to be the wrong direction to visually
+ // differentiate between hits and misses
+ color = &guiPalette->getColor(Palette::HIT_MONSTER_PLAYER);
+ }
else
- font = hitRedFont;
+ {
+ color = &guiPalette->getColor(Palette::MISS);
+ }
+ }
+ else if (getType() == MONSTER)
+ {
+ color = &guiPalette->getColor(Palette::HIT_PLAYER_MONSTER);
+ }
+ else
+ {
+ color = &guiPalette->getColor(Palette::HIT_MONSTER_PLAYER);
}
// Show damage number
- particleEngine->addTextSplashEffect(damage, 255, 255, 255, font,
+ particleEngine->addTextSplashEffect(damage,
#ifdef TMWSERV_SUPPORT
(int) mPos.x + 16,
- (int) mPos.y + 16);
+ (int) mPos.y + 16,
#else
- mPx + 16, mPy + 16);
+ mPx + 16, mPy + 16,
#endif
- effectManager->trigger(26, this);
-}
-
-void Being::showCrit()
-{
- effectManager->trigger(28, this);
+ color, font, true);
+ if (amount > 0)
+ {
+ if (type != CRITICAL)
+ {
+ effectManager->trigger(26, this);
+ }
+ else
+ {
+ effectManager->trigger(28, this);
+ }
+ }
}
#ifdef TMWSERV_SUPPORT
void Being::handleAttack()
#else
-void Being::handleAttack(Being *victim, int damage)
+void Being::handleAttack(Being *victim, int damage, AttackType type)
#endif
{
setAction(Being::ATTACK);
@@ -507,13 +504,10 @@ void Being::setAction(Action action, int attackType)
break;
case ATTACK:
if (mEquippedWeapon)
- {
currentAction = mEquippedWeapon->getAttackType();
- }
else
- {
currentAction = ACTION_ATTACK;
- }
+
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
if (mSprites[i])
@@ -584,21 +578,13 @@ SpriteDirection Being::getSpriteDirection() const
SpriteDirection dir;
if (mDirection & UP)
- {
dir = DIRECTION_UP;
- }
else if (mDirection & DOWN)
- {
dir = DIRECTION_DOWN;
- }
else if (mDirection & RIGHT)
- {
dir = DIRECTION_RIGHT;
- }
else
- {
- dir = DIRECTION_LEFT;
- }
+ dir = DIRECTION_LEFT;
return dir;
}
@@ -645,7 +631,7 @@ void Being::logic()
if (mSpeechTime > 0)
mSpeechTime--;
- // Remove text if speech boxes aren't being used
+ // Remove text and speechbubbles if speech boxes aren't being used
if (mSpeechTime == 0 && mText)
{
delete mText;
@@ -749,9 +735,7 @@ void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
#endif
if (mUsedTargetCursor)
- {
mUsedTargetCursor->draw(graphics, px, py);
- }
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
@@ -774,39 +758,44 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
return;
#ifdef TMWSERV_SUPPORT
- const int px = (int) mPos.x + offsetX + 3;
- const int py = (int) mPos.y + offsetY - 60;
+ const int px = (int) mPos.x + offsetX;
+ const int py = (int) mPos.y + offsetY - 64;
#else
- const int px = mPx + offsetX + 3;
- const int py = mPy + offsetY - 60;
+ const int px = mPx - offsetX;
+ const int py = mPy - offsetY - 64;
#endif
const int emotionIndex = mEmotion - 1;
if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast())
- emotionSet[emotionIndex]->draw(graphics, px, py);
+ EmoteDB::getAnimation(emotionIndex)->draw(graphics, px, py);
}
void Being::drawSpeech(int offsetX, int offsetY)
{
#ifdef TMWSERV_SUPPORT
- int px = (int) mPos.x + offsetX;
- int py = (int) mPos.y + offsetY;
+ int px = (int) mPos.x - offsetX;
+ int py = (int) mPos.y - offsetY;
#else
- const int px = mPx + offsetX;
- const int py = mPy + offsetY;
+ const int px = mPx - offsetX;
+ const int py = mPy - offsetY;
#endif
const int speech = (int) config.getValue("speech", NAME_IN_BUBBLE);
// Draw speech above this being
- if (mSpeechTime > 0 && (speech == NAME_IN_BUBBLE ||
- speech == NO_NAME_IN_BUBBLE))
+ if (mSpeechTime == 0)
+ {
+ if (mSpeechBubble->isVisible())
+ mSpeechBubble->setVisible(false);
+ }
+ else if (mSpeechTime > 0 && (speech == NAME_IN_BUBBLE ||
+ speech == NO_NAME_IN_BUBBLE))
{
const bool showName = (speech == NAME_IN_BUBBLE);
if (mText)
{
delete mText;
- mText = 0;
+ mText = NULL;
}
mSpeechBubble->setCaption(showName ? mName : "", mNameColor);
@@ -822,24 +811,24 @@ void Being::drawSpeech(int offsetX, int offsetY)
else if (mSpeechTime > 0 && speech == TEXT_OVERHEAD)
{
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));
+ gcn::Graphics::CENTER,
+ &guiPalette->getColor(Palette::PARTICLE));
}
else if (speech == NO_SPEECH)
{
mSpeechBubble->setVisible(false);
+
if (mText)
delete mText;
+
mText = NULL;
}
- else if (mSpeechTime == 0)
- {
- mSpeechBubble->setVisible(false);
- }
}
Being::Type Being::getType() const
@@ -908,24 +897,18 @@ int Being::getOffset(char pos, char neg) const
{
// Check whether we're walking in the requested direction
if (mAction != WALK || !(mDirection & (pos | neg)))
- {
return 0;
- }
int offset = (get_elapsed_time(mWalkTime) * 32) / mWalkSpeed;
// We calculate the offset _from_ the _target_ location
offset -= 32;
if (offset > 0)
- {
offset = 0;
- }
// Going into negative direction? Invert the offset.
if (mDirection & pos)
- {
offset = -offset;
- }
return offset;
}
@@ -1057,58 +1040,42 @@ void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
}
}
-
-
-
-static int hairStylesNr;
-static int hairColorsNr;
-static std::vector<std::string> hairColors;
-
-static void initializeHair();
-
-int Being::getHairStylesNr()
+int Being::getHairStyleCount()
{
- initializeHair();
- return hairStylesNr;
+ return mNumberOfHairstyles;
}
-int Being::getHairColorsNr()
+int Being::getHairColorCount()
{
- initializeHair();
- return hairColorsNr;
+ return mNumberOfHairColors;
}
std::string Being::getHairColor(int index)
{
- initializeHair();
- if (index < 0 || index >= hairColorsNr)
+ if (index < 0 || index >= mNumberOfHairColors)
return "#000000";
return hairColors[index];
}
-static bool hairInitialized = false;
-
-static void initializeHair()
+void Being::load()
{
- if (hairInitialized)
- return;
-
- // Hairstyles are encoded as negative numbers. Count how far negative we
- // can go.
- int hairstylesCtr = -1;
- while (ItemDB::get(hairstylesCtr).getSprite(GENDER_MALE) != "error.xml")
- --hairstylesCtr;
+ // Hairstyles are encoded as negative numbers. Count how far negative
+ // we can go.
+ int hairstyles = 1;
- hairStylesNr = -hairstylesCtr; // done.
- if (hairStylesNr == 0)
- hairStylesNr = 1; // No hair style -> no hair
-
- hairColorsNr = 0;
+ while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != "error.xml")
+ {
+ hairstyles++;
+ }
+ mNumberOfHairstyles = hairstyles;
XML::Document doc(HAIR_FILE);
xmlNodePtr root = doc.rootNode();
+ // Add an initial hair color
+ hairColors.resize(1, "#000000");
+
if (!root || !xmlStrEqual(root->name, BAD_CAST "colors"))
{
logger->log("Error loading being hair configuration file");
@@ -1121,20 +1088,13 @@ static void initializeHair()
std::string value = XML::getProperty(node, "value", "");
if (index >= 0 && !value.empty()) {
- if (index >= hairColorsNr) {
- hairColorsNr = index + 1;
- hairColors.resize(hairColorsNr, "#000000");
+ if (index >= mNumberOfHairColors) {
+ mNumberOfHairColors = index + 1;
+ hairColors.resize(mNumberOfHairColors, "#000000");
}
hairColors[index] = value;
}
}
}
- } // done initializing
-
- if (hairColorsNr == 0) { // No colors -> black only
- hairColorsNr = 1;
- hairColors.resize(hairColorsNr, "#000000");
}
-
- hairInitialized = 1;
}
diff --git a/src/being.h b/src/being.h
index a704b3df..e9805d9b 100644
--- a/src/being.h
+++ b/src/being.h
@@ -134,22 +134,32 @@ class Being : public Sprite
NUM_SPEECH
};
+ enum AttackType
+ {
+ HIT = 0x00,
+ CRITICAL = 0x0a,
+ MULTI = 0x08,
+ REFLECT = 0x04,
+ FLEE = 0x0b
+ };
+
/**
* Directions, to be used as bitmask values
*/
enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 };
#ifdef EATHENA_SUPPORT
- Uint16 mX, mY; /**< Tile coordinates */
- Uint16 mFrame;
- Uint16 mWalkTime;
+ Uint16 mX, mY; /**< Tile coordinates */
+ int mFrame;
+ int mWalkTime;
#endif
- Uint8 mEmotion; /**< Currently showing emotion */
- Uint8 mEmotionTime; /**< Time until emotion disappears */
+ int mEmotion; /**< Currently showing emotion */
+ int mEmotionTime; /**< Time until emotion disappears */
+ int mSpeechTime;
- Uint16 mAttackSpeed; /**< Attack speed */
- Action mAction; /**< Action the being is performing */
- Uint16 mJob; /**< Job (player job, npc, monster, creature ) */
+ int mAttackSpeed; /**< Attack speed */
+ Action mAction; /**< Action the being is performing */
+ Uint16 mJob; /**< Job (player job, npc, monster, creature ) */
/**
* Constructor.
@@ -197,30 +207,28 @@ class Being : public Sprite
* @param text The text that should appear.
* @param time The amount of time the text should stay in milliseconds.
*/
- void setSpeech(const std::string &text, Uint32 time = 500);
+ void setSpeech(const std::string &text, int time = 500);
/**
* Puts a damage bubble above this being.
*
- * @param amount The amount of damage.
+ * @param attacker the attacking being
+ * @param damage the amount of damage recieved (0 means miss)
+ * @param type the attack type
*/
- virtual void takeDamage(int amount);
-
- /**
- * Puts a crit notification bubble above this being.
- */
- virtual void showCrit();
+ virtual void takeDamage(Being *attacker, int damage, AttackType type);
/**
* Handles an attack of another being by this being.
*
- * @param victim The attacked being.
- * @param damage The amount of damage dealt (0 means miss).
+ * @param victim the victim being
+ * @param damage the amount of damage dealt (0 means miss)
+ * @param type the attack type
*/
#ifdef TMWSERV_SUPPORT
virtual void handleAttack();
#else
- virtual void handleAttack(Being *victim, int damage);
+ virtual void handleAttack(Being *victim, int damage, AttackType type);
#endif
/**
@@ -240,14 +248,12 @@ class Being : public Sprite
/**
* Gets the hair color for this being.
*/
- int getHairColor() const
- { return mHairColor; }
+ int getHairColor() const { return mHairColor; }
/**
* Gets the hair style for this being.
*/
- int getHairStyle() const
- { return mHairStyle; }
+ int getHairStyle() const { return mHairStyle; }
/**
* Get the number of hairstyles implemented
@@ -324,12 +330,12 @@ class Being : public Sprite
/**
* Gets the being id.
*/
- Uint32 getId() const { return mId; }
+ int getId() const { return mId; }
/**
* Sets the sprite id.
*/
- void setId(Uint32 id) { mId = id; }
+ void setId(int id) { mId = id; }
/**
* Sets the map the being is on
@@ -479,8 +485,6 @@ class Being : public Sprite
*/
void untarget() { mUsedTargetCursor = NULL; }
- AnimatedSprite* getEmote(int index) { return emotionSet[index]; }
-
void setEmote(Uint8 emotion, Uint8 emote_time)
{
mEmotion = emotion;
@@ -523,15 +527,17 @@ class Being : public Sprite
// Target cursor being used by the being
Image *mTargetCursor;
- static int getHairColorsNr();
+ static int getHairColorCount();
- static int getHairStylesNr();
+ static int getHairStyleCount();
static std::string getHairColor(int index);
virtual AnimatedSprite* getSprite(int index) const
{ return mSprites[index]; }
+ static void load();
+
protected:
/**
* Sets the new path for this being.
@@ -578,7 +584,7 @@ class Being : public Sprite
*/
virtual void handleStatusEffect(StatusEffect *effect, int effectId);
- Uint32 mId; /**< Unique sprite id */
+ int mId; /**< Unique sprite id */
Uint8 mDirection; /**< Facing direction */
#ifdef TMWSERV_SUPPORT
Uint8 mSpriteDirection; /**< Facing direction */
@@ -592,6 +598,8 @@ class Being : public Sprite
/** Engine-related infos about weapon. */
const ItemInfo* mEquippedWeapon;
+ static std::vector<std::string> hairColors;
+ static int mNumberOfHairColors; /** Number of hair colors in use */
static int mNumberOfHairstyles; /** Number of hair styles in use */
Path mPath;
@@ -600,12 +608,11 @@ class Being : public Sprite
int mHairStyle;
int mHairColor;
Gender mGender;
- Uint32 mSpeechTime;
- Sint32 mPx, mPy; /**< Pixel coordinates */
+ int mPx, mPy; /**< Pixel coordinates */
Uint16 mStunMode; /**< Stun mode; zero if not stunned */
std::set<int> mStatusEffects; /**< set of active status effects */
- gcn::Color mNameColor;
+ const gcn::Color* mNameColor;
std::vector<AnimatedSprite*> mSprites;
std::vector<int> mSpriteIDs;
@@ -641,9 +648,6 @@ class Being : public Sprite
// Target cursor being used
SimpleAnimation* mUsedTargetCursor;
-
- static int instances; /**< Number of Being instances */
- static std::vector<AnimatedSprite*> emotionSet; /**< Emoticons used by beings */
};
#endif
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index d2cac6ad..643d887f 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -66,6 +66,11 @@ BeingManager::BeingManager(Network *network):
}
#endif
+BeingManager::~BeingManager()
+{
+ clear();
+}
+
void BeingManager::setMap(Map *map)
{
mMap = map;
@@ -82,7 +87,7 @@ void BeingManager::setPlayer(LocalPlayer *player)
#ifdef TMWSERV_SUPPORT
Being* BeingManager::createBeing(int id, int type, int subtype)
#else
-Being* BeingManager::createBeing(Uint32 id, Uint16 job)
+Being *BeingManager::createBeing(int id, Uint16 job)
#endif
{
Being *being;
@@ -103,17 +108,17 @@ Being* BeingManager::createBeing(Uint32 id, Uint16 job)
assert(false);
}
#else
- if (job < 10)
+ if (job <= 25 || (job >= 4001 && job <= 4049))
being = new Player(id, job, mMap);
- else if (job >= 50 && job < 1002)
+ else if (job >= 46 && job <= 1000)
being = new NPC(id, job, mMap, mNetwork);
- else if (job >= 1002 && job < 1500)
+ else if (job > 1000 && job <= 2000)
being = new Monster(id, job, mMap);
else
being = new Being(id, job, mMap);
// Player or NPC
- if (job < 1002)
+ if (job <= 1000 || (job >= 4001 && job <= 4049))
{
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x0094);
@@ -135,7 +140,7 @@ void BeingManager::destroyBeing(Being *being)
delete being;
}
-Being* BeingManager::findBeing(Uint32 id)
+Being *BeingManager::findBeing(int id)
{
for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
{
@@ -147,7 +152,7 @@ Being* BeingManager::findBeing(Uint32 id)
return NULL;
}
-Being* BeingManager::findBeing(Uint16 x, Uint16 y, Being::Type type)
+Being *BeingManager::findBeing(int x, int y, Being::Type type)
{
beingFinder.x = x;
beingFinder.y = y;
@@ -158,7 +163,7 @@ Being* BeingManager::findBeing(Uint16 x, Uint16 y, Being::Type type)
return (i == mBeings.end()) ? NULL : *i;
}
-Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y)
+Being *BeingManager::findBeingByPixel(int x, int y)
{
BeingIterator itr = mBeings.begin();
BeingIterator itr_end = mBeings.end();
@@ -184,20 +189,19 @@ Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y)
return NULL;
}
-Being* BeingManager::findBeingByName(std::string name, Being::Type type)
+Being *BeingManager::findBeingByName(std::string name, Being::Type type)
{
for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
{
Being *being = (*i);
- if (being->getName() == name
- && (type == Being::UNKNOWN
- || type == being->getType()))
+ if (being->getName() == name &&
+ (type == Being::UNKNOWN || type == being->getType()))
return being;
}
return NULL;
}
-Beings& BeingManager::getAll()
+Beings &BeingManager::getAll()
{
return mBeings;
}
@@ -228,20 +232,16 @@ void BeingManager::logic()
void BeingManager::clear()
{
if (player_node)
- {
mBeings.remove(player_node);
- }
delete_all(mBeings);
mBeings.clear();
if (player_node)
- {
mBeings.push_back(player_node);
- }
}
-Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
+Being *BeingManager::findNearestLivingBeing(int x, int y, int maxdist,
Being::Type type)
{
Being *closestBeing = NULL;
@@ -274,8 +274,7 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
if ((being->getType() == type || type == Being::UNKNOWN)
&& (d < dist || closestBeing == NULL) // it is closer
- && being->mAction != Being::DEAD // no dead beings
- )
+ && being->mAction != Being::DEAD) // no dead beings
{
dist = d;
closestBeing = being;
@@ -285,7 +284,7 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
return (maxdist >= dist) ? closestBeing : NULL;
}
-Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
+Being *BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
Being::Type type)
{
Being *closestBeing = NULL;
@@ -313,8 +312,7 @@ Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
if ((being->getType() == type || type == Being::UNKNOWN)
&& (d < dist || closestBeing == NULL) // it is closer
&& being->mAction != Being::DEAD // no dead beings
- && being != aroundBeing
- )
+ && being != aroundBeing)
{
dist = d;
closestBeing = being;
@@ -323,3 +321,13 @@ Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
return (maxdist >= dist) ? closestBeing : NULL;
}
+
+bool BeingManager::hasBeing(Being *being)
+{
+ for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
+ {
+ if (being == *i) return true;
+ }
+
+ return false;
+}
diff --git a/src/beingmanager.h b/src/beingmanager.h
index 726a73ec..05821bcf 100644
--- a/src/beingmanager.h
+++ b/src/beingmanager.h
@@ -40,6 +40,8 @@ class BeingManager
BeingManager(Network *network);
#endif
+ ~BeingManager();
+
/**
* Sets the map on which beings are created
*/
@@ -56,7 +58,7 @@ class BeingManager
#ifdef TMWSERV_SUPPORT
Being *createBeing(int id, int type, int subtype);
#else
- Being *createBeing(Uint32 id, Uint16 job);
+ Being *createBeing(int id, Uint16 job);
#endif
/**
@@ -67,13 +69,13 @@ class BeingManager
/**
* Returns a specific id Being.
*/
- Being* findBeing(Uint32 id);
+ Being *findBeing(int id);
/**
* Returns a being at specific coordinates.
*/
- Being* findBeing(Uint16 x, Uint16 y, Being::Type type = Being::UNKNOWN);
- Being* findBeingByPixel(Uint16 x, Uint16 y);
+ Being *findBeing(int x, int y, Being::Type type = Being::UNKNOWN);
+ Being *findBeingByPixel(int x, int y);
/**
* Returns a being nearest to specific coordinates.
@@ -84,21 +86,21 @@ class BeingManager
* no being is returned.
* @param type The type of being to look for.
*/
- Being* findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
+ Being *findNearestLivingBeing(int x, int y, int maxdist,
Being::Type type = Being::UNKNOWN);
- /**
- * Finds a being by name and (optionally) by type.
- */
- Being* findBeingByName(std::string name, Being::Type type = Being::UNKNOWN);
-
- /**
- * Returns a being nearest to another being.
- *
- * \param maxdist maximal distance. If minimal distance is larger,
- * no being is returned
- */
- Being* findNearestLivingBeing(Being *aroundBeing, int maxdist,
+ /**
+ * Finds a being by name and (optionally) by type.
+ */
+ Being *findBeingByName(std::string name, Being::Type type = Being::UNKNOWN);
+
+ /**
+ * Returns a being nearest to another being.
+ *
+ * \param maxdist maximal distance. If minimal distance is larger,
+ * no being is returned
+ */
+ Being *findNearestLivingBeing(Being *aroundBeing, int maxdist,
Being::Type type = Being::UNKNOWN);
/**
@@ -107,6 +109,14 @@ class BeingManager
Beings& getAll();
/**
+ * Returns true if the given being is in the manager's list, false
+ * otherwise.
+ *
+ * \param being the being to search for
+ */
+ bool hasBeing(Being *being);
+
+ /**
* Logic.
*/
void logic();
diff --git a/src/engine.cpp b/src/engine.cpp
index 872ecd57..3b982694 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -44,8 +44,6 @@
#include "utils/stringutils.h"
-char itemCurrenyQ[10] = "0";
-
#ifdef TMWSERV_SUPPORT
Engine::Engine():
mCurrentMap(NULL)
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index fbe606b4..000835ad 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -26,10 +26,10 @@
#include "resources/image.h"
-FloorItem::FloorItem(unsigned int id,
- unsigned int itemId,
- unsigned short x,
- unsigned short y,
+FloorItem::FloorItem(int id,
+ int itemId,
+ int x,
+ int y,
Map *map):
mId(id),
mX(x),
@@ -51,7 +51,7 @@ FloorItem::~FloorItem()
delete mItem;
}
-unsigned int FloorItem::getItemId() const
+int FloorItem::getItemId() const
{
return mItem->getId();
}
diff --git a/src/floor_item.h b/src/floor_item.h
index 444c756a..7ca0f5a3 100644
--- a/src/floor_item.h
+++ b/src/floor_item.h
@@ -42,10 +42,10 @@ class FloorItem : public Sprite
/**
* Constructor.
*/
- FloorItem(unsigned int id,
- unsigned int itemId,
- unsigned short x,
- unsigned short y,
+ FloorItem(int id,
+ int itemId,
+ int x,
+ int y,
Map *map);
/**
@@ -56,22 +56,22 @@ class FloorItem : public Sprite
/**
* Returns instance id of this item.
*/
- unsigned int getId() const { return mId; }
+ int getId() const { return mId; }
/**
* Returns the item id.
*/
- unsigned int getItemId() const;
+ int getItemId() const;
/**
* Returns the x coordinate.
*/
- unsigned short getX() const { return mX; }
+ int getX() const { return mX; }
/**
* Returns the y coordinate.
*/
- unsigned short getY() const { return mY; }
+ int getY() const { return mY; }
/**
* Returns the pixel y coordinate.
@@ -88,8 +88,8 @@ class FloorItem : public Sprite
void draw(Graphics *graphics, int offsetX, int offsetY) const;
private:
- unsigned int mId;
- unsigned short mX, mY;
+ int mId;
+ int mX, mY;
Item *mItem;
Sprites::iterator mSpriteIterator;
Map *mMap;
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
index 65556abb..65fb2146 100644
--- a/src/flooritemmanager.cpp
+++ b/src/flooritemmanager.cpp
@@ -29,8 +29,8 @@ FloorItemManager::~FloorItemManager()
clear();
}
-FloorItem* FloorItemManager::create(unsigned int id, unsigned int itemId,
- unsigned short x, unsigned short y, Map *map)
+FloorItem* FloorItemManager::create(int id, int itemId,
+ int x, int y, Map *map)
{
FloorItem *floorItem = new FloorItem(id, itemId, x, y, map);
mFloorItems.push_back(floorItem);
@@ -49,7 +49,7 @@ void FloorItemManager::clear()
mFloorItems.clear();
}
-FloorItem* FloorItemManager::findById(unsigned int id)
+FloorItem *FloorItemManager::findById(int id)
{
FloorItemIterator i;
for (i = mFloorItems.begin(); i != mFloorItems.end(); i++)
@@ -63,8 +63,7 @@ FloorItem* FloorItemManager::findById(unsigned int id)
return NULL;
}
-FloorItem* FloorItemManager::findByCoordinates(unsigned short x,
- unsigned short y)
+FloorItem *FloorItemManager::findByCoordinates(int x, int y)
{
FloorItemIterator i;
for (i = mFloorItems.begin(); i != mFloorItems.end(); i++)
diff --git a/src/flooritemmanager.h b/src/flooritemmanager.h
index 3f96b587..704b39fd 100644
--- a/src/flooritemmanager.h
+++ b/src/flooritemmanager.h
@@ -32,15 +32,14 @@ class FloorItemManager
public:
~FloorItemManager();
- FloorItem* create(unsigned int id, unsigned int itemId,
- unsigned short x, unsigned short y, Map *map);
+ FloorItem* create(int id, int itemId, int x, int y, Map *map);
void destroy(FloorItem *item);
void clear();
- FloorItem* findById(unsigned int id);
- FloorItem* findByCoordinates(unsigned short x, unsigned short y);
+ FloorItem* findById(int id);
+ FloorItem* findByCoordinates(int x, int y);
private:
typedef std::list<FloorItem*> FloorItems;
diff --git a/src/game.cpp b/src/game.cpp
index 79eaf9c5..b1542891 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -83,6 +83,8 @@
#include "gui/npcpostdialog.h"
#include "gui/partywindow.h"
#include "gui/quitdialog.h"
+#else
+#include "gui/storagewindow.h"
#endif
#ifdef TMWSERV_SUPPORT
@@ -144,7 +146,9 @@ StatusWindow *statusWindow;
MiniStatusWindow *miniStatusWindow;
BuyDialog *buyDialog;
SellDialog *sellDialog;
+#ifdef EATHENA_SUPPORT
BuySellDialog *buySellDialog;
+#endif
InventoryWindow *inventoryWindow;
EmoteWindow *emoteWindow;
NpcIntegerDialog *npcIntegerDialog;
@@ -158,8 +162,9 @@ GuildWindow *guildWindow;
MagicDialog *magicDialog;
NpcPostDialog *npcPostDialog;
PartyWindow *partyWindow;
+#else
+StorageWindow *storageWindow;
#endif
-Setup* setupWindow;
Minimap *minimap;
EquipmentWindow *equipmentWindow;
TradeWindow *tradeWindow;
@@ -189,9 +194,9 @@ namespace {
{
void action(const gcn::ActionEvent &event)
{
- if (event.getId() == "yes" || event.getId() == "ok") {
+ if (event.getId() == "yes" || event.getId() == "ok")
done = true;
- }
+
#ifdef EATHENA_SUPPORT
exitConfirm = NULL;
#endif
@@ -224,13 +229,9 @@ Uint32 nextSecond(Uint32 interval, void *param)
int get_elapsed_time(int start_time)
{
if (start_time <= tick_time)
- {
return (tick_time - start_time) * 10;
- }
else
- {
return (tick_time + (MAX_TIME - start_time)) * 10;
- }
}
/**
@@ -248,6 +249,10 @@ void createGuiWindows(Network *network)
buyDialog = new BuyDialog;
sellDialog = new SellDialog;
tradeWindow = new TradeWindow;
+ npcTextDialog = new NpcTextDialog;
+ npcIntegerDialog = new NpcIntegerDialog;
+ npcListDialog = new NpcListDialog;
+ npcStringDialog = new NpcStringDialog;
npcPostDialog = new NpcPostDialog();
magicDialog = new MagicDialog();
equipmentWindow = new EquipmentWindow(player_node->mEquipment.get());
@@ -258,45 +263,57 @@ void createGuiWindows(Network *network)
chatWindow = new ChatWindow(network);
buyDialog = new BuyDialog(network);
sellDialog = new SellDialog(network);
+ buySellDialog = new BuySellDialog(network);
tradeWindow = new TradeWindow(network);
equipmentWindow = new EquipmentWindow;
+ npcTextDialog = new NpcTextDialog(network);
+ npcIntegerDialog = new NpcIntegerDialog(network);
+ npcListDialog = new NpcListDialog(network);
+ npcStringDialog = new NpcStringDialog(network);
+ storageWindow = new StorageWindow(network);
#endif
menuWindow = new MenuWindow;
statusWindow = new StatusWindow(player_node);
miniStatusWindow = new MiniStatusWindow;
- buySellDialog = new BuySellDialog;
inventoryWindow = new InventoryWindow;
emoteWindow = new EmoteWindow;
- npcTextDialog = new NpcTextDialog;
- npcIntegerDialog = new NpcIntegerDialog;
- npcListDialog = new NpcListDialog;
- npcStringDialog = new NpcStringDialog;
skillDialog = new SkillDialog;
- setupWindow = new Setup;
minimap = new Minimap;
helpWindow = new HelpWindow;
debugWindow = new DebugWindow;
- itemShortcutWindow = new ShortcutWindow("ItemShortcut",new ItemShortcutContainer);
- emoteShortcutWindow = new ShortcutWindow("emoteShortcut",new EmoteShortcutContainer);
+ itemShortcutWindow = new ShortcutWindow("ItemShortcut",
+ new ItemShortcutContainer);
+ emoteShortcutWindow = new ShortcutWindow("emoteShortcut",
+ new EmoteShortcutContainer);
// Set initial window visibility
chatWindow->setVisible((bool) config.getValue(
chatWindow->getWindowName() + "Visible", true));
miniStatusWindow->setVisible((bool) config.getValue(
- miniStatusWindow->getWindowName() + "Visible", true));
+ miniStatusWindow->getPopupName() + "Visible", true));
buyDialog->setVisible(false);
sellDialog->setVisible(false);
minimap->setVisible((bool) config.getValue(
minimap->getWindowName() + "Visible", true));
tradeWindow->setVisible(false);
menuWindow->setVisible((bool) config.getValue(
- menuWindow->getWindowName() + "Visible", true));
+ menuWindow->getPopupName() + "Visible", true));
itemShortcutWindow->setVisible((bool) config.getValue(
itemShortcutWindow->getWindowName() + "Visible", true));
emoteShortcutWindow->setVisible((bool) config.getValue(
emoteShortcutWindow->getWindowName() + "Visible", true));
minimap->setVisible((bool) config.getValue(
minimap->getWindowName() + "Visible", true));
+#ifdef EATHENA_SUPPORT
+ buySellDialog->setVisible(false);
+#endif
+ npcTextDialog->setVisible(false);
+ npcIntegerDialog->setVisible(false);
+ npcListDialog->setVisible(false);
+ npcStringDialog->setVisible(false);
+#ifdef EATHENA_SUPPORT
+ storageWindow->setVisible(false);
+#endif
if (config.getValue("logToChat", 0))
{
@@ -316,7 +333,9 @@ void destroyGuiWindows()
delete menuWindow;
delete buyDialog;
delete sellDialog;
+#ifdef EATHENA_SUPPORT
delete buySellDialog;
+#endif
delete inventoryWindow;
delete emoteWindow;
delete npcIntegerDialog;
@@ -331,7 +350,6 @@ void destroyGuiWindows()
delete partyWindow;
#endif
delete skillDialog;
- delete setupWindow;
delete minimap;
delete equipmentWindow;
delete tradeWindow;
@@ -339,6 +357,9 @@ void destroyGuiWindows()
delete debugWindow;
delete itemShortcutWindow;
delete emoteShortcutWindow;
+#ifdef EATHENA_SUPPORT
+ delete storageWindow;
+#endif
}
#ifdef TMWSERV_SUPPORT
@@ -361,6 +382,7 @@ Game::Game(Network *network):
mNpcHandler(new NPCHandler),
mPlayerHandler(new PlayerHandler),
mTradeHandler(new TradeHandler),
+ mLastTarget(Being::UNKNOWN),
mLogicCounterId(0), mSecondsCounterId(0)
{
done = false;
@@ -447,6 +469,8 @@ Game::Game(Network *network):
engine->changeMap(map_path);
#endif
+
+ setupWindow->setInGame(true);
}
Game::~Game()
@@ -457,10 +481,10 @@ Game::~Game()
delete playerParty;
#endif
- delete player_node;
destroyGuiWindows();
delete beingManager;
+ delete player_node;
delete floorItemManager;
delete channelManager;
delete commandHandler;
@@ -530,8 +554,11 @@ void Game::optionChanged(const std::string &name)
{
int fpsLimit = (int) config.getValue("fpslimit", 0);
- // Calculate new minimum frame time
- mMinFrameTime = fpsLimit ? 1000 / fpsLimit : 0;
+ // Calculate new minimum frame time. If one isn't set, use 60 FPS.
+ // (1000 / 60 is 16.66) Since the client can go well above the refresh
+ // rates for monitors now in OpenGL mode, this cutoff is done to help
+ // conserve on CPU time.
+ mMinFrameTime = fpsLimit ? 1000 / fpsLimit : 16;
// Reset draw time to current time
mDrawTime = tick_time * 10;
@@ -598,8 +625,9 @@ void Game::logic()
if (!disconnectedDialog)
{
disconnectedDialog = new OkDialog(_("Network Error"),
- _("The connection to the server was lost, "
- "the program will now quit"));
+ _("The connection to the "
+ "server was lost, the "
+ "program will now quit"));
disconnectedDialog->addActionListener(&exitListener);
disconnectedDialog->requestMoveToTop();
}
@@ -625,7 +653,7 @@ void Game::handleInput()
gcn::Window *requestedWindow = NULL;
if (setupWindow->isVisible() &&
- keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
+ keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
{
keyboard.setNewKey((int) event.key.keysym.sym);
keyboard.callbackNewKey();
@@ -663,47 +691,41 @@ void Game::handleInput()
}
}
- if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) ||
- keyboard.isKeyActive(keyboard.KEY_OK))
- {
- // Input chat window
- if (!(chatWindow->isInputFocused() ||
- deathNotice ||
- weightNotice))
+ if (!(chatWindow->isInputFocused() || deathNotice || weightNotice))
+ if (keyboard.isKeyActive(keyboard.KEY_OK))
{
#ifdef TMWSERV_SUPPORT
// Don not focus chat input when quit dialog is active
if (quitDialog != NULL && quitDialog->isVisible())
continue;
#else
- // Quit by pressing Enter if the exit confirm is there
if (exitConfirm &&
keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT))
done = true;
#endif
// Close the Browser if opened
else if (helpWindow->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
helpWindow->setVisible(false);
// Close the config window, cancelling changes if opened
else if (setupWindow->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
setupWindow->action(gcn::ActionEvent(NULL, "cancel"));
// Submits the text and proceeds to the next dialog
else if (npcStringDialog->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
npcStringDialog->action(gcn::ActionEvent(NULL, "ok"));
// Proceed to the next dialog option, or close the window
else if (npcTextDialog->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
npcTextDialog->action(gcn::ActionEvent(NULL, "ok"));
// Choose the currently highlighted dialogue option
else if (npcListDialog->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
npcListDialog->action(gcn::ActionEvent(NULL, "ok"));
// Submits the text and proceeds to the next dialog
else if (npcIntegerDialog->isVisible() &&
- keyboard.isKeyActive(keyboard.KEY_OK))
+ keyboard.isKeyActive(keyboard.KEY_OK))
npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok"));
/*
else if (guildWindow->isVisible())
@@ -711,22 +733,12 @@ void Game::handleInput()
// TODO: Check if a dialog is open and close it if so
}
*/
- else if (!(keyboard.getKeyValue(
- KeyboardConfig::KEY_TOGGLE_CHAT) ==
- keyboard.getKeyValue(
- KeyboardConfig::KEY_OK) &&
- (helpWindow->isVisible() ||
- setupWindow->isVisible() ||
- npcStringDialog->isVisible() ||
- npcTextDialog->isVisible() ||
- npcListDialog->isVisible() ||
- npcIntegerDialog->isVisible())))
- {
- chatWindow->requestChatFocus();
+ }
+ if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT))
+ {
+ if (chatWindow->requestChatFocus())
used = true;
- }
}
- }
const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
switch (tKey)
@@ -1054,8 +1066,7 @@ void Game::handleInput()
if (keyboard.isKeyActive(keyboard.KEY_ATTACK) ||
(joystick && joystick->buttonPressed(0)))
{
- Being *target = beingManager->findNearestLivingBeing(x, y, 20,
- Being::MONSTER);
+ Being *target = NULL;
bool newTarget = !keyboard.isKeyActive(keyboard.KEY_TARGET);
// A set target has highest priority
@@ -1072,59 +1083,50 @@ void Game::handleInput()
default: break;
}
- // Attack priorioty is: Monster, Player, auto target
- target = beingManager->findBeing(targetX, targetY, Being::MONSTER);
- if (!target)
- target = beingManager->findBeing(targetX, targetY, Being::PLAYER);
+ // Only auto target Monsters
+ target = beingManager->findNearestLivingBeing(targetX, targetY,
+ 20, Being::MONSTER);
}
player_node->attack(target, newTarget);
}
#endif
- // Target the nearest player if 'q' is pressed
- if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) &&
- !keyboard.isKeyActive(keyboard.KEY_TARGET) )
- {
- Being *target = beingManager->findNearestLivingBeing(player_node, 20, Being::PLAYER);
-
- player_node->setTarget(target);
- }
-
- // Target the nearest monster if 'a' pressed
- if ((keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ||
+ // Target the nearest player/monster/npc
+ if ((keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) ||
+ keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ||
+ keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) ||
(joystick && joystick->buttonPressed(3))) &&
!keyboard.isKeyActive(keyboard.KEY_TARGET))
{
- Being *target = beingManager->findNearestLivingBeing(
- x, y, 20, Being::MONSTER);
-
- player_node->setTarget(target);
- }
-
- // Target the nearest npc if 'n' pressed
- if ( keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) &&
- !keyboard.isKeyActive(keyboard.KEY_TARGET) )
- {
- Being *target = beingManager->findNearestLivingBeing(
- x, y, 20, Being::NPC);
-
- player_node->setTarget(target);
- }
+ Being::Type currentTarget = Being::UNKNOWN;
+ if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ||
+ (joystick && joystick->buttonPressed(3)))
+ currentTarget = Being::MONSTER;
+ else if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER))
+ currentTarget = Being::PLAYER;
+ else if (keyboard.isKeyActive(keyboard.KEY_TARGET_NPC))
+ currentTarget = Being::NPC;
+
+ Being *target = beingManager->findNearestLivingBeing(player_node,
+ 20, currentTarget);
+
+ if (target && (target != player_node->getTarget() ||
+ currentTarget != mLastTarget))
+ {
+ player_node->setTarget(target);
+ mLastTarget = currentTarget;
+ }
+ } else mLastTarget = Being::UNKNOWN; // Reset last target
// Talk to the nearest NPC if 't' pressed
if ( keyboard.isKeyActive(keyboard.KEY_TALK) )
{
- if (!npcTextDialog->isVisible() && !npcListDialog->isVisible())
+ if (!npcTextDialog->isVisible() && !npcListDialog->isVisible() &&
+ !npcStringDialog->isVisible() && !npcIntegerDialog->isVisible())
{
Being *target = player_node->getTarget();
- if (!target)
- {
- target = beingManager->findNearestLivingBeing(
- x, y, 20, Being::NPC);
- }
-
if (target)
{
if (target->getType() == Being::NPC)
diff --git a/src/game.h b/src/game.h
index 7eecc036..c537d147 100644
--- a/src/game.h
+++ b/src/game.h
@@ -83,6 +83,8 @@ class Game : public ConfigListener
MessageHandlerPtr mPostHandler;
MessageHandlerPtr mTradeHandler;
+ int mLastTarget;
+
SDL_TimerID mLogicCounterId;
SDL_TimerID mSecondsCounterId;
};
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 4af7b723..b9bd9fa6 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -49,30 +49,25 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
mFullscreen = fs;
mHWAccel = hwaccel;
- if (fs) {
+ if (fs)
displayFlags |= SDL_FULLSCREEN;
- }
- if (hwaccel) {
+ if (hwaccel)
displayFlags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
- } else {
+ else
displayFlags |= SDL_SWSURFACE;
- }
mScreen = SDL_SetVideoMode(w, h, bpp, displayFlags);
- if (!mScreen) {
+ if (!mScreen)
return false;
- }
char videoDriverName[64];
- if (SDL_VideoDriverName(videoDriverName, 64)) {
+ if (SDL_VideoDriverName(videoDriverName, 64))
logger->log("Using video driver: %s", videoDriverName);
- }
- else {
+ else
logger->log("Using video driver: unknown");
- }
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
@@ -103,9 +98,8 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
bool Graphics::setFullscreen(bool fs)
{
- if (mFullscreen == fs) {
+ if (mFullscreen == fs)
return true;
- }
return setVideoMode(mScreen->w, mScreen->h,
mScreen->format->BitsPerPixel, fs, mHWAccel);
@@ -127,7 +121,7 @@ bool Graphics::drawImage(Image *image, int x, int y)
}
bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
- int width, int height, bool)
+ int width, int height, bool)
{
// Check that preconditions for blitting are met.
if (!mScreen || !image || !image->mImage) return false;
@@ -149,7 +143,7 @@ bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
}
void Graphics::drawImage(gcn::Image const *image, int srcX, int srcY,
- int dstX, int dstY, int width, int height)
+ int dstX, int dstY, int width, int height)
{
ProxyImage const *srcImage =
dynamic_cast< ProxyImage const * >(image);
@@ -159,22 +153,34 @@ void Graphics::drawImage(gcn::Image const *image, int srcX, int srcY,
void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h)
{
- int iw = image->getWidth();
- int ih = image->getHeight();
- if (iw == 0 || ih == 0) return;
+ // Check that preconditions for blitting are met.
+ if (!mScreen || !image || !image->mImage) return;
+
+ const int iw = image->getWidth();
+ const int ih = image->getHeight();
+
+ if (iw == 0 || ih == 0) return;
- int px = 0; // X position on pattern plane
- int py = 0; // Y position on pattern plane
+ for (int py = 0; py < h; py += ih) // Y position on pattern plane
+ {
+ int dh = (py + ih >= h) ? h - py : ih;
+ int srcY = image->mBounds.y;
+ int dstY = y + py + mClipStack.top().yOffset;
- while (py < h) {
- while (px < w) {
+ for (int px = 0; px < w; px += iw) // X position on pattern plane
+ {
int dw = (px + iw >= w) ? w - px : iw;
- int dh = (py + ih >= h) ? h - py : ih;
- drawImage(image, 0, 0, x + px, y + py, dw, dh);
- px += iw;
+ int srcX = image->mBounds.x;
+ int dstX = x + px + mClipStack.top().xOffset;
+
+ SDL_Rect dstRect;
+ SDL_Rect srcRect;
+ dstRect.x = dstX; dstRect.y = dstY;
+ srcRect.x = srcX; srcRect.y = srcY;
+ srcRect.w = dw; srcRect.h = dh;
+
+ SDL_BlitSurface(image->mImage, &srcRect, mScreen, &dstRect);
}
- py += ih;
- px = 0;
}
}
diff --git a/src/graphics.h b/src/graphics.h
index 172032dc..c4004ffc 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -48,6 +48,19 @@ struct SDL_Surface;
*/
struct ImageRect
{
+ enum ImagePosition
+ {
+ UPPER_LEFT = 0,
+ UPPER_CENTER = 1,
+ UPPER_RIGHT = 2,
+ LEFT = 3,
+ CENTER = 4,
+ RIGHT = 5,
+ LOWER_LEFT = 6,
+ LOWER_CENTER = 7,
+ LOWER_RIGHT = 8,
+ };
+
Image *grid[9];
};
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 7c0ae1a7..2f667237 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -24,8 +24,8 @@
#include <guichan/graphics.hpp>
#include "browserbox.h"
-#include "color.h"
#include "linkhandler.h"
+#include "palette.h"
#include "truetypefont.h"
BrowserBox::BrowserBox(unsigned int mode, bool opaque):
@@ -225,6 +225,7 @@ struct MouseOverLink
void BrowserBox::mousePressed(gcn::MouseEvent &event)
{
+ if (!mLinkHandler) return;
LinkIterator i = find_if(mLinks.begin(), mLinks.end(),
MouseOverLink(event.getX(), event.getY()));
@@ -243,18 +244,20 @@ void BrowserBox::mouseMoved(gcn::MouseEvent &event)
void BrowserBox::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
if (mOpaque)
{
- graphics->setColor(gcn::Color(BGCOLOR));
+ graphics->setColor(guiPalette->getColor(Palette::BACKGROUND));
graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
}
if (mSelectedLink >= 0)
{
- bool valid;
if ((mHighMode & BACKGROUND))
{
- graphics->setColor(gcn::Color(textColor->getColor('H', valid)));
+ graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT));
graphics->fillRectangle(gcn::Rectangle(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y1,
@@ -265,7 +268,7 @@ void BrowserBox::draw(gcn::Graphics *graphics)
if ((mHighMode & UNDERLINE))
{
- graphics->setColor(gcn::Color(textColor->getColor('<', valid)));
+ graphics->setColor(guiPalette->getColor(Palette::HYPERLINK));
graphics->drawLine(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y2,
@@ -279,11 +282,11 @@ void BrowserBox::draw(gcn::Graphics *graphics)
int link = 0;
TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont());
- graphics->setColor(BLACK);
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
for (TextRowIterator i = mTextRows.begin(); i != mTextRows.end(); i++)
{
- int selColor = BLACK;
- int prevColor = selColor;
+ const gcn::Color *selColor = &guiPalette->getColor(Palette::TEXT);
+ const gcn::Color *prevColor = selColor;
std::string row = *(i);
bool wrapped = false;
x = 0;
@@ -331,7 +334,7 @@ void BrowserBox::draw(gcn::Graphics *graphics)
else
{
bool valid;
- int rgb = textColor->getColor(c, valid);
+ const gcn::Color *col = &guiPalette->getColor(c, valid);
if (c == '<')
{
const int size = mLinks[link].x2 - mLinks[link].x1;
@@ -344,7 +347,7 @@ void BrowserBox::draw(gcn::Graphics *graphics)
}
if (valid)
{
- selColor = rgb;
+ selColor = col;
}
}
start += 3;
@@ -354,7 +357,7 @@ void BrowserBox::draw(gcn::Graphics *graphics)
break;
}
}
- graphics->setColor(gcn::Color(selColor));
+ graphics->setColor(*selColor);
}
std::string::size_type len =
diff --git a/src/gui/button.cpp b/src/gui/button.cpp
index 1d3a04e4..f9e5e9dc 100644
--- a/src/gui/button.cpp
+++ b/src/gui/button.cpp
@@ -23,6 +23,7 @@
#include <guichan/font.hpp>
#include "button.h"
+#include "palette.h"
#include "../configuration.h"
#include "../graphics.h"
@@ -72,9 +73,9 @@ Button::Button(const std::string& caption, const std::string &actionEventId,
{
init();
setActionEventId(actionEventId);
- if (listener) {
+
+ if (listener)
addActionListener(listener);
- }
}
void Button::init()
@@ -93,8 +94,10 @@ void Button::init()
{
btn[mode] = resman->getImage(data[mode].file);
a = 0;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
button[mode].grid[a] = btn[mode]->getSubImage(
data[x].gridX, data[y].gridY,
data[x + 1].gridX - data[x].gridX + 1,
@@ -150,7 +153,7 @@ void Button::draw(gcn::Graphics *graphics)
static_cast<Graphics*>(graphics)->
drawImageRect(0, 0, getWidth(), getHeight(), button[mode]);
- graphics->setColor(getForegroundColor());
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
int textX;
int textY = getHeight() / 2 - getFont()->getHeight() / 2;
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 53a586c3..0b572a23 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "buy.h"
+#include "label.h"
#include "scrollarea.h"
#include "shop.h"
#include "shoplistbox.h"
@@ -56,29 +55,34 @@ BuyDialog::BuyDialog(Network *network):
{
setWindowName("Buy");
setResizable(true);
+ setCloseButton(true);
setMinWidth(260);
setMinHeight(230);
- setDefaultSize(0, 0, 260, 230);
+ setDefaultSize(260, 230, ImageRect::CENTER);
mShopItems = new ShopItems;
mShopItemList = new ShopListBox(mShopItems, mShopItems);
mScrollArea = new ScrollArea(mShopItemList);
+ mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+
mSlider = new Slider(1.0);
- mQuantityLabel = new gcn::Label("0");
+ mQuantityLabel = new Label(strprintf("%d / %d", mAmountItems, mMaxItems));
+ mQuantityLabel->setAlignment(gcn::Graphics::CENTER);
mMoneyLabel = new gcn::Label(strprintf(_("Price: %s / Total: %s"),
"", ""));
+
mIncreaseButton = new Button("+", "+", this);
mDecreaseButton = new Button("-", "-", this);
mBuyButton = new Button(_("Buy"), "buy", this);
mQuitButton = new Button(_("Quit"), "quit", this);
- mItemDescLabel = new gcn::Label(strprintf(_("Description: %s"), ""));
- mItemEffectLabel = new gcn::Label(strprintf(_("Effect: %s"), ""));
+ mAddMaxButton = new Button(_("Max"), "max", this);
+ mItemDescLabel = new Label(strprintf(_("Description: %s"), ""));
+ mItemEffectLabel = new Label(strprintf(_("Effect: %s"), ""));
- mIncreaseButton->setSize(20, 20);
- mDecreaseButton->setSize(20, 20);
+ mDecreaseButton->adjustSize();
+ mDecreaseButton->setWidth(mIncreaseButton->getWidth());
- mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mIncreaseButton->setEnabled(false);
mDecreaseButton->setEnabled(false);
mBuyButton->setEnabled(false);
@@ -88,21 +92,26 @@ BuyDialog::BuyDialog(Network *network):
mSlider->addActionListener(this);
mShopItemList->addSelectionListener(this);
- place(0, 0, mScrollArea, 5).setPadding(3);
- place(0, 1, mQuantityLabel, 2);
- place(2, 1, mSlider, 3);
- place(0, 2, mMoneyLabel, 5);
- place(0, 3, mItemEffectLabel, 5);
- place(0, 4, mItemDescLabel, 5);
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+
+ place(0, 0, mScrollArea, 8, 5).setPadding(3);
place(0, 5, mDecreaseButton);
- place(1, 5, mIncreaseButton);
- place(3, 5, mBuyButton);
- place(4, 5, mQuitButton);
+ place(1, 5, mSlider, 3);
+ place(4, 5, mIncreaseButton);
+ place(5, 5, mQuantityLabel, 2);
+ place(7, 5, mAddMaxButton);
+ place(0, 6, mMoneyLabel, 8);
+ place(0, 7, mItemEffectLabel, 8);
+ place(0, 8, mItemDescLabel, 8);
+ place(6, 9, mBuyButton);
+ place(7, 9, mQuitButton);
+
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
+ center();
loadWindowState();
- setLocationRelativeTo(getParent());
}
BuyDialog::~BuyDialog()
@@ -138,15 +147,14 @@ void BuyDialog::addItem(int id, int amount, int price)
void BuyDialog::action(const gcn::ActionEvent &event)
{
- int selectedItem = mShopItemList->getSelected();
-
if (event.getId() == "quit")
{
- setVisible(false);
- if (current_npc) current_npc->handleDeath();
+ close();
return;
}
+ int selectedItem = mShopItemList->getSelected();
+
// The following actions require a valid selection
if (selectedItem < 0 ||
selectedItem >= (int) mShopItems->getNumberOfElements())
@@ -171,6 +179,12 @@ void BuyDialog::action(const gcn::ActionEvent &event)
mSlider->setValue(mAmountItems);
updateButtonsAndLabels();
}
+ else if (event.getId() == "max")
+ {
+ mAmountItems = mMaxItems;
+ mSlider->setValue(mAmountItems);
+ updateButtonsAndLabels();
+ }
// TODO: Actually we'd have a bug elsewhere if this check for the number
// of items to be bought ever fails, Bertram removed the assertions, is
// there a better way to ensure this fails in an _obvious_ way in C++?
@@ -257,3 +271,24 @@ void BuyDialog::updateButtonsAndLabels()
Units::formatCurrency(price).c_str(),
Units::formatCurrency(mMoney - price).c_str()));
}
+
+void BuyDialog::logic()
+{
+ Window::logic();
+
+ if (!current_npc) setVisible(false);
+}
+
+void BuyDialog::setVisible(bool visible)
+{
+ Window::setVisible(visible);
+
+ if (visible)
+ requestFocus();
+}
+
+void BuyDialog::close()
+{
+ setVisible(false);
+ current_npc = 0;
+}
diff --git a/src/gui/buy.h b/src/gui/buy.h
index 5510ccc6..200394b9 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -101,12 +101,27 @@ class BuyDialog : public Window, public gcn::ActionListener,
*/
void updateButtonsAndLabels();
+ /**
+ * Check for current NPC
+ */
+ void logic();
+
+ /**
+ * Sets the visibility of this window.
+ */
+ void setVisible(bool visible);
+
+ /**
+ * Closes the Buy Window, as well as resetting the current npc.
+ */
+ void close();
private:
#ifdef EATHENA_SUPPORT
Network *mNetwork;
#endif
gcn::Button *mBuyButton;
gcn::Button *mQuitButton;
+ gcn::Button *mAddMaxButton;
gcn::Button *mIncreaseButton;
gcn::Button *mDecreaseButton;
ShopListBox *mShopItemList;
@@ -124,4 +139,6 @@ class BuyDialog : public Window, public gcn::ActionListener,
int mMaxItems;
};
+extern BuyDialog *buyDialog;
+
#endif
diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp
index 2d39eac7..c56f6435 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -24,11 +24,17 @@
#include "../npc.h"
+#include "../net/messageout.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
+
#include "../utils/gettext.h"
-BuySellDialog::BuySellDialog():
- Window(_("Shop"))
+BuySellDialog::BuySellDialog(Network *network):
+ Window(_("Shop")), mNetwork(network)
{
+ setWindowName("BuySell");
Button *buyButton = 0;
static const char *buttonNames[] = {
N_("Buy"), N_("Sell"), N_("Cancel"), 0
@@ -46,19 +52,53 @@ BuySellDialog::BuySellDialog():
buyButton->requestFocus();
setContentSize(x, 2 * y + buyButton->getHeight());
- setLocationRelativeTo(getParent());
- requestFocus();
+ center();
+ setDefaultSize();
+ loadWindowState();
+}
+
+void BuySellDialog::logic()
+{
+ Window::logic();
+
+ if (isVisible() && !current_npc)
+ setVisible(false);
+}
+
+void BuySellDialog::setVisible(bool visible)
+{
+ Window::setVisible(visible);
+
+ if (visible)
+ requestFocus();
}
void BuySellDialog::action(const gcn::ActionEvent &event)
{
- if (event.getId() == "Buy") {
- current_npc->buy();
- } else if (event.getId() == "Sell") {
- current_npc->sell();
- } else if (event.getId() == "Cancel") {
- if (current_npc) current_npc->handleDeath();
- }
setVisible(false);
+ int action = 0;
+
+ NPC::isTalking = false;
+
+ if (event.getId() == "Buy")
+ {
+ action = 0;
+ }
+ else if (event.getId() == "Sell")
+ {
+ action = 1;
+ }
+ else if (event.getId() == "Cancel")
+ {
+ current_npc = 0;
+ return;
+ }
+
+#ifdef EATHENA_SUPPORT
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST);
+ outMsg.writeInt32(current_npc);
+ outMsg.writeInt8(action);
+#endif
}
diff --git a/src/gui/buysell.h b/src/gui/buysell.h
index e3cdc52a..4b137554 100644
--- a/src/gui/buysell.h
+++ b/src/gui/buysell.h
@@ -26,6 +26,8 @@
#include "window.h"
+class Network;
+
/**
* A dialog to choose between buying or selling at a shop.
*
@@ -40,12 +42,24 @@ class BuySellDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
- BuySellDialog();
+ BuySellDialog(Network *network);
+
+ /**
+ * Check for current NPC
+ */
+ void logic();
+
+ void setVisible(bool visible);
/**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+
+ private:
+ Network *mNetwork;
};
+extern BuySellDialog *buySellDialog;
+
#endif
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index e4f560ce..7c0e2ab2 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -23,11 +23,10 @@
#include <guichan/font.hpp>
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "char_select.h"
#include "confirm_dialog.h"
+#include "label.h"
#include "ok_dialog.h"
#include "playerbox.h"
#include "textfield.h"
@@ -63,6 +62,8 @@
#include "../utils/strprintf.h"
#include "../utils/stringutils.h"
+#define MAX_SLOT 2
+
// Defined in main.cpp, used here for setting the char create dialog
extern CharServerHandler charServerHandler;
@@ -114,8 +115,8 @@ CharSelectDialog::CharSelectDialog(Network *network,
mCancelButton = new Button(_("Cancel"), "cancel", this);
mPreviousButton = new Button(_("Previous"), "previous", this);
mNextButton = new Button(_("Next"), "next", this);
- mNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
- mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
+ mNameLabel = new Label(strprintf(_("Name: %s"), ""));
+ mLevelLabel = new Label(strprintf(_("Level: %d"), 0));
#ifdef TMWSERV_SUPPORT
mNewCharButton = new Button(_("New"), "new", this);
mDelCharButton = new Button(_("Delete"), "delete", this);
@@ -123,10 +124,10 @@ CharSelectDialog::CharSelectDialog(Network *network,
mChangePasswordButton = new Button(_("Change Password"), "change_password", this);
mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this);
- mAccountNameLabel = new gcn::Label(strprintf(_("Account: %s"), mLoginData->username.c_str()));
- mNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
- mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
- mMoneyLabel = new gcn::Label(strprintf(_("Money: %d"), 0));
+ mAccountNameLabel = new Label(strprintf(_("Account: %s"), mLoginData->username.c_str()));
+ mNameLabel = new Label(strprintf(_("Name: %s"), ""));
+ mLevelLabel = new Label(strprintf(_("Level: %d"), 0));
+ mMoneyLabel = new Label(strprintf(_("Money: %d"), 0));
// Control that shows the Player
mPlayerBox = new PlayerBox;
@@ -161,8 +162,8 @@ CharSelectDialog::CharSelectDialog(Network *network,
mPlayerBox = new PlayerBox;
mPlayerBox->setWidth(74);
- mJobLevelLabel = new gcn::Label(strprintf(_("Job Level: %d"), 0));
- mMoneyLabel = new gcn::Label(strprintf(_("Money: %s"), mMoney.c_str()));
+ mJobLevelLabel = new Label(strprintf(_("Job Level: %d"), 0));
+ mMoneyLabel = new Label(strprintf(_("Money: %s"), mMoney.c_str()));
const std::string tempString = getFont()->getWidth(_("New")) <
getFont()->getWidth(_("Delete")) ?
@@ -189,7 +190,7 @@ CharSelectDialog::CharSelectDialog(Network *network,
reflowLayout(250, 0);
#endif
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
mSelectButton->requestFocus();
updatePlayerInfo();
@@ -252,11 +253,11 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
else if (event.getId() == "newdel")
{
// Check for a character
- if (mCharInfo->getEntry() && n_character <= MAX_SLOT + 1)
+ if (mCharInfo->getEntry())
{
new CharDeleteConfirm(this);
}
- else
+ else if (n_character <= MAX_SLOT)
{
// Start new character dialog
CharCreateDialog *charCreateDialog =
@@ -421,13 +422,13 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
rand() % numberOfHairColors);
mNameField = new TextField("");
- mNameLabel = new gcn::Label(_("Name:"));
+ mNameLabel = new Label(_("Name:"));
mNextHairColorButton = new Button(">", "nextcolor", this);
mPrevHairColorButton = new Button("<", "prevcolor", this);
- mHairColorLabel = new gcn::Label(_("Hair Color:"));
+ mHairColorLabel = new Label(_("Hair Color:"));
mNextHairStyleButton = new Button(">", "nextstyle", this);
mPrevHairStyleButton = new Button("<", "prevstyle", this);
- mHairStyleLabel = new gcn::Label(_("Hair Style:"));
+ mHairStyleLabel = new Label(_("Hair Style:"));
mCreateButton = new Button(_("Create"), "create", this);
mCancelButton = new Button(_("Cancel"), "cancel", this);
#ifdef TMWSERV_SUPPORT
@@ -545,7 +546,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
reflowLayout(225, 0);
#endif
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
mNameField->requestFocus();
}
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index fa03bdc2..5cfcef4d 100644
--- a/src/gui/char_server.cpp
+++ b/src/gui/char_server.cpp
@@ -85,7 +85,7 @@ ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState):
// Select first server
mServerList->setSelected(1);
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
mOkButton->requestFocus();
}
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index a072704b..597eddfd 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -71,7 +71,7 @@ ChatWindow::ChatWindow(Network * network):
setWindowName("Chat");
setResizable(true);
- setDefaultSize(0, windowContainer->getHeight() - 123, 600, 123);
+ setDefaultSize(600, 123, ImageRect::LOWER_LEFT);
setMinWidth(150);
setMinHeight(90);
@@ -121,7 +121,15 @@ ChatWindow::~ChatWindow()
config.setValue("PartyPrefix", partyPrefix);
config.setValue("ReturnToggles", mReturnToggles ? "1" : "0");
delete mRecorder;
+ delete mParty;
#endif
+ delete mItemLinkHandler;
+}
+
+void ChatWindow::resetToDefaultSize()
+{
+ mRecorder->resetToDefaultSize();
+ Window::resetToDefaultSize();
}
void ChatWindow::widgetResized(const gcn::Event &event)
@@ -303,6 +311,42 @@ void ChatWindow::chatLog(std::string line, int own, std::string channelName,
<< (int) ((t / 60) % 60)
<< "] ";
+ // Check for item link
+ std::string::size_type start = tmp.text.find('[');
+ while (start != std::string::npos && tmp.text[start+1] != '@')
+ {
+ std::string::size_type end = tmp.text.find(']', start);
+ if (start+1 != end && end != std::string::npos)
+ {
+ // Catch multiple embeds and ignore them
+ // so it doesn't crash the client.
+ while ((tmp.text.find('[', start + 1) != std::string::npos) &&
+ (tmp.text.find('[', start + 1) < end))
+ {
+ start = tmp.text.find('[', start + 1);
+ }
+
+ std::string temp = tmp.text.substr(start+1, end - start - 1);
+
+ trim(temp);
+
+ for (unsigned int i = 0; i < temp.size(); i++)
+ {
+ temp[i] = (char) tolower(temp[i]);
+ }
+
+ const ItemInfo itemInfo = ItemDB::get(temp);
+ if (itemInfo.getName() != _("Unknown item"))
+ {
+ tmp.text.insert(end, "@@");
+ tmp.text.insert(start+1, "|");
+ tmp.text.insert(start+1, toString(itemInfo.getId()));
+ tmp.text.insert(start+1, "@@");
+ }
+ }
+ start = tmp.text.find('[', start + 1);
+ }
+
line = lineColor + timeStr.str() + tmp.nick + tmp.text;
// We look if the Vertical Scroll Bar is set at the max before
@@ -370,7 +414,7 @@ void ChatWindow::action(const gcn::ActionEvent &event)
}
}
-void ChatWindow::requestChatFocus()
+bool ChatWindow::requestChatFocus()
{
// Make sure chatWindow is visible
if (!isVisible())
@@ -385,9 +429,14 @@ void ChatWindow::requestChatFocus()
mTmpVisible = true;
}
+ // Don't do anything else if the input is already visible and has focus
+ if (mChatInput->isVisible() && mChatInput->isFocused())
+ return false;
+
// Give focus to the chat input
mChatInput->setVisible(true);
mChatInput->requestFocus();
+ return true;
}
bool ChatWindow::isInputFocused()
@@ -488,38 +537,6 @@ void ChatWindow::chatSend(std::string &msg)
}
#endif
- // Check for item link
- std::string::size_type start = msg.find('[');
- while (start != std::string::npos && msg[start+1] != '@')
- {
- std::string::size_type end = msg.find(']', start);
- if (start+1 != end && end != std::string::npos)
- {
- // Catch multiple embeds and ignore them
- // so it doesn't crash the client.
- while ((msg.find('[', start + 1) != std::string::npos) &&
- (msg.find('[', start + 1) < end))
- {
- start = msg.find('[', start + 1);
- }
-
- std::string temp = msg.substr(start + 1, end - start - 1);
-
- toLower(trim(temp));
-
- const ItemInfo itemInfo = ItemDB::get(temp);
- if (itemInfo.getName() != _("Unknown item"))
- {
- msg.insert(end, "@@");
- msg.insert(start+1, "|");
- msg.insert(start+1, toString(itemInfo.getId()));
- msg.insert(start+1, "@@");
- }
- }
- start = msg.find('[', start + 1);
- }
-
-
// Prepare ordinary message
if (msg[0] != '/')
{
diff --git a/src/gui/chat.h b/src/gui/chat.h
index 972ecf9a..3c553c67 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -100,6 +100,12 @@ class ChatWindow : public Window,
void logic();
/**
+ * Reset the chat window and recorder window attached to it to their
+ * default positions.
+ */
+ void resetToDefaultSize();
+
+ /**
* Adds a line of text to our message list. Parameters:
*
* @param line Text message.
@@ -129,8 +135,11 @@ class ChatWindow : public Window,
/**
* Request focus for typing chat message.
+ *
+ * \returns true if the input was shown
+ * false otherwise
*/
- void requestChatFocus();
+ bool requestChatFocus();
/**
* Checks whether ChatWindow is Focused or not.
@@ -248,14 +257,15 @@ class ChatWindow : public Window,
typedef std::list<std::string> History;
typedef History::iterator HistoryIterator;
- History mHistory; /**< Command history. */
- HistoryIterator mCurHist; /**< History iterator. */
- Recorder *mRecorder; /**< Recording class */
- bool mReturnToggles; /**< Marks whether <Return> toggles the chat log
- or not */
+ History mHistory; /**< Command history */
+ HistoryIterator mCurHist; /**< History iterator */
+ Recorder *mRecorder; /**< Recording class */
+ bool mReturnToggles; /**< Marks whether <Return> toggles the chat
+ log or not */
#ifdef EATHENA_SUPPORT
- char mPartyPrefix; /**< Messages beginning with the prefix are sent to
- the party */
+ char mPartyPrefix; /**< Messages beginning with the prefix are
+ sent to the party */
+ Party *mParty;
#endif
};
diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp
index 7fa4fa81..5695a23f 100644
--- a/src/gui/checkbox.cpp
+++ b/src/gui/checkbox.cpp
@@ -20,6 +20,7 @@
*/
#include "checkbox.h"
+#include "palette.h"
#include "../configuration.h"
#include "../graphics.h"
@@ -68,6 +69,18 @@ CheckBox::~CheckBox()
}
}
+void CheckBox::draw(gcn::Graphics* graphics)
+{
+ drawBox(graphics);
+
+ graphics->setFont(getFont());
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+
+ const int h = getHeight() + getHeight() / 2;
+
+ graphics->drawText(getCaption(), h - 2, 0);
+}
+
void CheckBox::drawBox(gcn::Graphics* graphics)
{
Image *box;
diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h
index 20adb43c..dd59493c 100644
--- a/src/gui/checkbox.h
+++ b/src/gui/checkbox.h
@@ -45,6 +45,11 @@ class CheckBox : public gcn::CheckBox
~CheckBox();
/**
+ * Draws the caption, then calls drawBox to draw the check box.
+ */
+ void draw(gcn::Graphics* graphics);
+
+ /**
* Draws the check box, not the caption.
*/
void drawBox(gcn::Graphics* graphics);
diff --git a/src/gui/color.cpp b/src/gui/color.cpp
deleted file mode 100644
index f9b89857..00000000
--- a/src/gui/color.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Configurable text colors
- * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
- *
- * This file is part of The Mana World.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "color.h"
-
-#include "../configuration.h"
-
-#include "../utils/gettext.h"
-#include "../utils/stringutils.h"
-
-Color::Color()
-{
- addColor('C', 0x000000, _("Chat"));
- addColor('G', 0xff0000, _("GM"));
- addColor('H', 0xebc873, _("Highlight"));
- addColor('Y', 0x1fa052, _("Player"));
- addColor('W', 0x0000ff, _("Whisper"));
- addColor('I', 0xa08527, _("Is"));
- addColor('P', 0xff00d8, _("Party"));
- addColor('S', 0x8415e2, _("Server"));
- addColor('L', 0x919191, _("Logger"));
- addColor('<', 0xe50d0d, _("Hyperlink"));
- commit();
-}
-
-Color::~Color()
-{
- for (ColVector::iterator col = mColVector.begin(),
- colEnd = mColVector.end();
- col != colEnd;
- ++col)
- {
- config.setValue("Color" + col->text, toString(col->rgb));
- }
-}
-
-void Color::setColor(char c, int rgb)
-{
- for (ColVector::iterator col = mColVector.begin(),
- colEnd = mColVector.end();
- col != colEnd;
- ++col)
- {
- if (col->ch == c)
- {
- col->rgb = rgb;
- return;
- }
- }
-}
-
-int Color::getColor(char c, bool &valid) const
-{
- for (ColVector::const_iterator col = mColVector.begin(),
- colEnd = mColVector.end();
- col != colEnd;
- ++col)
- {
- if (col->ch == c)
- {
- valid = true;
- return col->rgb;
- }
- }
- valid = false;
- return 0x000000;
-}
-
-std::string Color::getElementAt(int i)
-{
- if (i < 0 || i >= getNumberOfElements())
- {
- return "";
- }
- return mColVector[i].text;
-}
-
-char Color::getColorCharAt(int i)
-{
- if (i < 0 || i >= getNumberOfElements())
- {
- return 'C';
- }
- return mColVector[i].ch;
-}
-
-void Color::addColor(char c, int rgb, const std::string &text)
-{
- int trueRgb = (int) config.getValue("Color" + text, rgb);
- mColVector.push_back(ColorElem(c, trueRgb, text));
-}
-
-int Color::getColorAt(int i)
-{
- if (i < 0 || i >= getNumberOfElements())
- {
- return 0;
- }
- return mColVector[i].rgb;
-}
-
-void Color::setColorAt(int i, int rgb)
-{
- if (i >= 0 && i < getNumberOfElements())
- {
- mColVector[i].rgb = rgb;
- }
-}
-
-void Color::commit()
-{
- for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
- i != iEnd;
- ++i)
- {
- i->committedRgb = i->rgb;
- }
-}
-
-void Color::rollback()
-{
- for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
- i != iEnd;
- ++i)
- {
- i->rgb = i->committedRgb;
- }
-}
diff --git a/src/gui/color.h b/src/gui/color.h
deleted file mode 100644
index 2816cedc..00000000
--- a/src/gui/color.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Configurable text colors
- * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
- *
- * This file is part of The Mana World.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef COLOR_H
-#define COLOR_H
-
-#include <string>
-#include <vector>
-
-#include <guichan/listmodel.hpp>
-
-class Color : public gcn::ListModel
-{
- public:
- /**
- * Constructor
- */
- Color();
-
- /**
- * Destructor
- */
- ~Color();
-
- /**
- * Define the color replacement for a character
- *
- * @param c charater to be replaced
- * @param rgb color to replace character
- */
- void setColor(char c, int rgb);
-
- /**
- * Define the color replacement for a character
- *
- * @param c character to be replaced
- * @param r red component
- * @param g green component
- * @param b blue component
- */
- void setColor(char c, int r, int g, int b)
- {
- setColor(c, (r << 16) | (g << 8) | b);
- }
-
- /**
- * Return the color associated with a character, if exists
- *
- * @param c character requested
- * @param valid indicate whether character is known
- */
- int getColor(char c, bool &valid) const;
-
- /**
- * Return the number of colors known
- */
- int getNumberOfElements() { return mColVector.size(); }
-
- /**
- * Return the name of the ith color
- *
- * @param i index of color interested in
- */
- std::string getElementAt(int i);
-
- /**
- * Get the color for the element at index i in the current color
- * model
- */
- int getColorAt(int i);
-
- /**
- * Get the character used by the color for the element at index i in
- * the current color model
- */
- char getColorCharAt(int i);
-
- /**
- * Set the color for the element at index i
- */
- void setColorAt(int i, int rgb);
-
- /**
- * Commit the colors
- */
- void commit();
-
- /**
- * Rollback the colors
- */
- void rollback();
-
- private:
- struct ColorElem
- {
- ColorElem(char c, int rgb, const std::string &text) :
- ch(c), rgb(rgb), text(text) {}
- char ch;
- int rgb;
- int committedRgb;
- std::string text;
- };
- typedef std::vector<ColorElem> ColVector;
- ColVector mColVector;
-
- /**
- * Initialise color
- *
- * @param c character that needs initialising
- * @param rgb default color if not found in config
- * @param text identifier of color
- */
- void addColor(char c, int rgb, const std::string &text);
-};
-
-extern Color *textColor;
-
-#endif
diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp
index 5ad2e26c..a40593e3 100644
--- a/src/gui/confirm_dialog.cpp
+++ b/src/gui/confirm_dialog.cpp
@@ -23,6 +23,7 @@
#include "button.h"
#include "confirm_dialog.h"
+#include "gui.h"
#include "scrollarea.h"
#include "textbox.h"
@@ -49,14 +50,16 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
int numRows = mTextBox->getNumberOfRows();
int width = getFont()->getWidth(title);
int inWidth = yesButton->getWidth() + noButton->getWidth() + 5;
+ const int fontHeight = getFont()->getHeight();
if (numRows > 1)
{
- // 15 == height of each line of text (based on font heights)
+ // fontHeight == height of each line of text (based on font heights)
// 14 == row top + bottom graphic pixel heights
- setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + noButton->getHeight());
+ setContentSize(mTextBox->getMinWidth() + fontHeight, ((numRows + 1) *
+ fontHeight) + noButton->getHeight());
mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
- 3 + (numRows * 14)));
+ 3 + (numRows * fontHeight)));
}
else
{
@@ -64,16 +67,17 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
width = getFont()->getWidth(msg);
if (width < inWidth)
width = inWidth;
- setContentSize(width + 15, 30 + noButton->getHeight());
+ setContentSize(width + fontHeight, (2 * fontHeight) +
+ noButton->getHeight());
mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
}
yesButton->setPosition(
(mTextBox->getMinWidth() - inWidth) / 2,
- (numRows * 14) + noButton->getHeight() - 8);
+ ((numRows - 1) * fontHeight) + noButton->getHeight() + 2);
noButton->setPosition(
yesButton->getX() + yesButton->getWidth() + 5,
- (numRows * 14) + noButton->getHeight() - 8);
+ ((numRows - 1) * fontHeight) + noButton->getHeight() + 2);
add(mTextArea);
add(yesButton);
@@ -81,7 +85,7 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
if (getParent())
{
- setLocationRelativeTo(getParent());
+ center();
getParent()->moveToTop(this);
}
setVisible(true);
@@ -104,7 +108,5 @@ void ConfirmDialog::action(const gcn::ActionEvent &event)
// Can we receive anything else anyway?
if (event.getId() == "yes" || event.getId() == "no")
- {
scheduleDelete();
- }
}
diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp
index fbf127de..5fb21ff2 100644
--- a/src/gui/connection.cpp
+++ b/src/gui/connection.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "connection.h"
+#include "label.h"
#include "progressbar.h"
#include "../main.h"
@@ -37,7 +36,7 @@ ConnectionDialog::ConnectionDialog(int previousState):
Button *cancelButton = new Button(_("Cancel"), "cancelButton", this);
mProgressBar = new ProgressBar(0.0, 200 - 10, 20, 128, 128, 128);
- gcn::Label *label = new gcn::Label(_("Connecting..."));
+ gcn::Label *label = new Label(_("Connecting..."));
cancelButton->setPosition(5, 100 - 5 - cancelButton->getHeight());
mProgressBar->setPosition(5, cancelButton->getY() - 25);
@@ -47,7 +46,7 @@ ConnectionDialog::ConnectionDialog(int previousState):
add(cancelButton);
add(mProgressBar);
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
}
diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp
index 2ed891db..a98c9af4 100644
--- a/src/gui/debugwindow.cpp
+++ b/src/gui/debugwindow.cpp
@@ -19,11 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <SDL_mouse.h>
-
-#include <guichan/widgets/label.hpp>
-
#include "debugwindow.h"
+#include "label.h"
#include "viewport.h"
#include "widgets/layout.h"
@@ -42,40 +39,38 @@ DebugWindow::DebugWindow():
setResizable(true);
setCloseButton(true);
- setDefaultSize(0, 0, 400, 60);
- loadWindowState();
+ setDefaultSize(400, 100, ImageRect::CENTER);
- mFPSLabel = new gcn::Label("0 FPS");
- mMusicFileLabel = new gcn::Label("Music: ");
- mMapLabel = new gcn::Label("Map: ");
- mMiniMapLabel = new gcn::Label("Mini-Map: ");
- mTileMouseLabel = new gcn::Label("Mouse: 0, 0");
- mParticleCountLabel = new gcn::Label("Particle count: 0");
+ mFPSLabel = new Label("0 FPS");
+ mMusicFileLabel = new Label("Music: ");
+ mMapLabel = new Label("Map: ");
+ mMiniMapLabel = new Label("Mini-Map: ");
+ mTileMouseLabel = new Label("Mouse: 0, 0");
+ mParticleCountLabel = new Label("Particle count: 0");
- place(0, 0, mFPSLabel);
+ place(0, 0, mFPSLabel, 3);
place(3, 0, mTileMouseLabel);
- place(0, 1, mMusicFileLabel, 2);
+ place(0, 1, mMusicFileLabel, 3);
place(3, 1, mParticleCountLabel);
- place(0, 2, mMapLabel, 2);
- place(0, 3, mMiniMapLabel, 2);
+ place(0, 2, mMapLabel, 4);
+ place(0, 3, mMiniMapLabel, 4);
- reflowLayout(375, 0);
+ loadWindowState();
}
void DebugWindow::logic()
{
+ if (!isVisible())
+ return;
+
// Get the current mouse position
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
- int mouseTileX = mouseX / 32 + viewport->getCameraX();
- int mouseTileY = mouseY / 32 + viewport->getCameraY();
+ int mouseTileX = (viewport->getMouseX() + viewport->getCameraX()) / 32;
+ int mouseTileY = (viewport->getMouseY() + viewport->getCameraY()) / 32;
mFPSLabel->setCaption(toString(fps) + " FPS");
- mFPSLabel->adjustSize();
- mTileMouseLabel->setCaption("Mouse: " +
- toString(mouseTileX) + ", " + toString(mouseTileY));
- mTileMouseLabel->adjustSize();
+ mTileMouseLabel->setCaption("Tile: (" + toString(mouseTileX) + ", " +
+ toString(mouseTileY) + ")");
Map *currentMap = engine->getCurrentMap();
if (currentMap)
@@ -83,20 +78,16 @@ void DebugWindow::logic()
const std::string music =
"Music: " + currentMap->getProperty("music");
mMusicFileLabel->setCaption(music);
- mMusicFileLabel->adjustSize();
const std::string minimap =
"MiniMap: " + currentMap->getProperty("minimap");
mMiniMapLabel->setCaption(minimap);
- mMiniMapLabel->adjustSize();
const std::string map =
"Map: " + currentMap->getProperty("_filename");
mMapLabel->setCaption(map);
- mMapLabel->adjustSize();
}
mParticleCountLabel->setCaption("Particle count: " +
toString(Particle::particleCount));
- mParticleCountLabel->adjustSize();
}
diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h
index e089de27..8097132c 100644
--- a/src/gui/debugwindow.h
+++ b/src/gui/debugwindow.h
@@ -50,4 +50,6 @@ class DebugWindow : public Window
gcn::Label *mParticleCountLabel;
};
+extern DebugWindow *debugWindow;
+
#endif
diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp
index e22b031b..ececd9aa 100644
--- a/src/gui/emotecontainer.cpp
+++ b/src/gui/emotecontainer.cpp
@@ -53,7 +53,7 @@ EmoteContainer::EmoteContainer():
// Setup emote sprites
for (int i = 0; i <= EmoteDB::getLast(); i++)
{
- mEmoteImg.push_back(player_node->getEmote(i));
+ mEmoteImg.push_back(EmoteDB::getAnimation(i));
}
mSelImg = resman->getImage("graphics/gui/selection.png");
@@ -78,13 +78,14 @@ EmoteContainer::~EmoteContainer()
void EmoteContainer::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
int columns = getWidth() / gridWidth;
// Have at least 1 column
if (columns < 1)
- {
columns = 1;
- }
for (int i = 0; i < mMaxEmote ; i++)
{
diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h
index fefce793..88df29fc 100644
--- a/src/gui/emotecontainer.h
+++ b/src/gui/emotecontainer.h
@@ -121,7 +121,7 @@ class EmoteContainer : public gcn::Widget,
*/
void distributeValueChangedEvent(void);
- std::vector<AnimatedSprite*> mEmoteImg;
+ std::vector<const AnimatedSprite*> mEmoteImg;
Image *mSelImg;
int mSelectedEmoteIndex;
diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp
index a0739723..661f42a7 100644
--- a/src/gui/emoteshortcutcontainer.cpp
+++ b/src/gui/emoteshortcutcontainer.cpp
@@ -20,6 +20,7 @@
*/
#include "emoteshortcutcontainer.h"
+#include "palette.h"
#include "../animatedsprite.h"
#include "../configuration.h"
@@ -59,7 +60,7 @@ EmoteShortcutContainer::EmoteShortcutContainer():
// Setup emote sprites
for (int i = 0; i <= EmoteDB::getLast(); i++)
{
- mEmoteImg.push_back(player_node->getEmote(i));
+ mEmoteImg.push_back(EmoteDB::getAnimation(i));
}
mMaxItems = EmoteDB::getLast() < MAX_ITEMS ? EmoteDB::getLast() : MAX_ITEMS;
@@ -75,6 +76,15 @@ EmoteShortcutContainer::~EmoteShortcutContainer()
void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ mBackgroundImg->setAlpha(mAlpha);
+ }
+
Graphics *g = static_cast<Graphics*>(graphics);
graphics->setFont(getFont());
@@ -89,12 +99,13 @@ void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
// Draw emote keyboard shortcut.
const char *key = SDL_GetKeyName(
(SDLKey) keyboard.getKeyValue(keyboard.KEY_EMOTE_1 + i));
- graphics->setColor(0x000000);
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT);
if (emoteShortcut->getEmote(i))
{
- mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2, emoteY + 10);
+ mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2,
+ emoteY + 10);
}
}
@@ -102,7 +113,7 @@ void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
if (mEmoteMoved)
{
// Draw the emote image being dragged by the cursor.
- AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1];
+ const AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1];
if (sprite)
{
const int tPosX = mCursorPosX - (sprite->getWidth() / 2);
@@ -111,12 +122,6 @@ void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
sprite->draw(g, tPosX, tPosY);
}
}
-
- if (config.getValue("guialpha", 0.8) != mAlpha)
- {
- mAlpha = config.getValue("guialpha", 0.8);
- mBackgroundImg->setAlpha(mAlpha);
- }
}
void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event)
@@ -129,9 +134,7 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event)
const int emoteId = emoteShortcut->getEmote(index);
if (index == -1)
- {
return;
- }
if (emoteId)
{
@@ -152,19 +155,17 @@ void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event)
const int index = getIndexFromGrid(event.getX(), event.getY());
if (index == -1)
- {
- return;
- }
+ return;
// Stores the selected emote if there is one.
if (emoteShortcut->isEmoteSelected())
{
- emoteShortcut->setEmote(index);
- emoteShortcut->setEmoteSelected(0);
+ emoteShortcut->setEmote(index);
+ emoteShortcut->setEmoteSelected(0);
}
else if (emoteShortcut->getEmote(index))
{
- mEmoteClicked = true;
+ mEmoteClicked = true;
}
}
@@ -175,9 +176,7 @@ void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event)
const int index = getIndexFromGrid(event.getX(), event.getY());
if (emoteShortcut->isEmoteSelected())
- {
emoteShortcut->setEmoteSelected(0);
- }
if (index == -1)
{
@@ -196,9 +195,7 @@ void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event)
}
if (mEmoteClicked)
- {
mEmoteClicked = false;
- }
}
}
diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h
index d32a9f79..2997cb09 100644
--- a/src/gui/emoteshortcutcontainer.h
+++ b/src/gui/emoteshortcutcontainer.h
@@ -68,7 +68,7 @@ class EmoteShortcutContainer : public ShortcutContainer
void mouseReleased(gcn::MouseEvent &event);
private:
- std::vector<AnimatedSprite*> mEmoteImg;
+ std::vector<const AnimatedSprite*> mEmoteImg;
bool mEmoteClicked;
int mEmoteMoved;
diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp
index 48635720..d4b3cf2e 100644
--- a/src/gui/emotewindow.cpp
+++ b/src/gui/emotewindow.cpp
@@ -40,7 +40,7 @@ EmoteWindow::EmoteWindow():
setCloseButton(true);
setMinWidth(80);
setMinHeight(130);
- setDefaultSize(115, 25, 322, 200);
+ setDefaultSize(322, 200, ImageRect::CENTER);
mUseButton = new Button(_("Use"), "use", this);
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index a44ae3ec..7ac9051f 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -27,6 +27,7 @@
#include "button.h"
#include "equipmentwindow.h"
#include "itempopup.h"
+#include "palette.h"
#include "playerbox.h"
#include "viewport.h"
@@ -71,6 +72,7 @@ EquipmentWindow::EquipmentWindow():
mSelected(-1)
{
mItemPopup = new ItemPopup;
+ mItemPopup->setOpaque(false);
// Control that shows the Player
mPlayerBox = new PlayerBox;
@@ -79,7 +81,7 @@ EquipmentWindow::EquipmentWindow():
setWindowName("Equipment");
setCloseButton(true);
- setDefaultSize(5, 195, 180, 300);
+ setDefaultSize(180, 300, ImageRect::CENTER);
loadWindowState();
mUnequip = new Button(_("Unequip"), "unequip", this);
@@ -119,6 +121,9 @@ EquipmentWindow::~EquipmentWindow()
void EquipmentWindow::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
// Draw window graphics
Window::draw(graphics);
@@ -132,6 +137,22 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
#endif
{
+ if (i == mSelected)
+ {
+ const gcn::Color color = guiPalette->getColor(Palette::HIGHLIGHT);
+
+ // Set color to the highligh color
+ g->setColor(gcn::Color(color.r, color.g, color.b, getGuiAlpha()));
+ g->fillRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY,
+ BOX_WIDTH, BOX_HEIGHT));
+ }
+
+ // Set color black.
+ g->setColor(gcn::Color(0, 0, 0));
+ // Draw box border.
+ g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY,
+ BOX_WIDTH, BOX_HEIGHT));
+
#ifdef TMWSERV_SUPPORT
Item *item = mEquipment->getEquipment(i);
#else
@@ -147,7 +168,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
#ifdef EATHENA_SUPPORT
if (i == EQUIP_AMMO_SLOT)
{
- g->setColor(gcn::Color(0, 0, 0));
+ g->setColor(guiPalette->getColor(Palette::TEXT));
graphics->drawText(toString(item->getQuantity()),
mEquipBox[i].posX + (BOX_WIDTH / 2),
mEquipBox[i].posY - getFont()->getHeight(),
@@ -155,21 +176,6 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
}
#endif
}
-
- if (i == mSelected)
- {
- // Set color red.
- g->setColor(gcn::Color(255, 0, 0));
- }
- else
- {
- // Set color black.
- g->setColor(gcn::Color(0, 0, 0));
- }
-
- // Draw box border.
- g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY,
- BOX_WIDTH, BOX_HEIGHT));
}
}
@@ -280,8 +286,9 @@ void EquipmentWindow::mouseMoved(gcn::MouseEvent &event)
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
- mItemPopup->setItem(item->getInfo());
- mItemPopup->setOpaque(false);
+ if (item->getInfo().getName() != mItemPopup->getItemName())
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->updateColors();
mItemPopup->view(x + getX(), y + getY());
}
else
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 1ef0219a..87ce74fa 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -25,7 +25,9 @@
#include "focushandler.h"
#include "gui.h"
+#include "palette.h"
#include "sdlinput.h"
+#include "skin.h"
#include "truetypefont.h"
#include "viewport.h"
#include "window.h"
@@ -46,11 +48,6 @@ Gui *gui = 0;
Viewport *viewport = 0; /**< Viewport on the map. */
SDLInput *guiInput = 0;
-// Fonts used in showing hits
-gcn::Font *hitRedFont = 0;
-gcn::Font *hitBlueFont = 0;
-gcn::Font *hitYellowFont = 0;
-
// Bolded font
gcn::Font *boldFont = 0;
@@ -113,6 +110,7 @@ Gui::Gui(Graphics *graphics):
{
const int fontSize = (int)config.getValue("fontSize", 11);
mGuiFont = new TrueTypeFont(path, fontSize);
+ mInfoParticleFont = new TrueTypeFont(path, fontSize, 1);
}
catch (gcn::Exception e)
{
@@ -136,22 +134,6 @@ Gui::Gui(Graphics *graphics):
gcn::Widget::setGlobalFont(mGuiFont);
- // Load hits' colorful fonts
- try
- {
- hitRedFont = new gcn::ImageFont("graphics/gui/hits_red.png",
- "0123456789crit! ");
- hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png",
- "0123456789crit! ");
- hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png",
- "0123456789misxp ");
- }
- catch (gcn::Exception e)
- {
- logger->error(std::string("Unable to load colored hits' fonts: ")
- + e.getMessage());
- }
-
// Initialize mouse cursor and listen for changes to the option
setUseCustomCursor(config.getValue("customcursor", 1) == 1);
mConfigListener = new GuiConfigListener(this);
@@ -169,16 +151,12 @@ Gui::~Gui()
config.removeListener("customcursor", mConfigListener);
delete mConfigListener;
- // Fonts used in showing hits
- delete hitRedFont;
- delete hitBlueFont;
- delete hitYellowFont;
-
if (mMouseCursors)
mMouseCursors->decRef();
delete mGuiFont;
delete boldFont;
+ delete mInfoParticleFont;
delete viewport;
delete getTop();
@@ -196,6 +174,8 @@ void Gui::logic()
else
mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f);
+ guiPalette->advanceGradient();
+
gcn::Gui::logic();
}
@@ -262,3 +242,8 @@ void Gui::handleMouseMoved(const gcn::MouseInput &mouseInput)
gcn::Gui::handleMouseMoved(mouseInput);
mMouseInactivityTimer = 0;
}
+
+const int Gui::getFontHeight() const
+{
+ return mGuiFont->getHeight();
+}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 5c0c24f7..2ce153db 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -77,6 +77,18 @@ class Gui : public gcn::Gui
{ return mGuiFont; }
/**
+ * Return game font height.
+ */
+ const int getFontHeight() const;
+
+ /**
+ * Return the Font used for "Info Particles", i.e. ones showing, what
+ * you picked up, etc.
+ */
+ gcn::Font* getInfoParticleFont() const
+ { return mInfoParticleFont; }
+
+ /**
* Sets whether a custom cursor should be rendered.
*/
void setUseCustomCursor(bool customCursor);
@@ -107,6 +119,7 @@ class Gui : public gcn::Gui
private:
GuiConfigListener *mConfigListener;
gcn::Font *mGuiFont; /**< The global GUI font */
+ gcn::Font *mInfoParticleFont; /**< Font for Info Particles*/
bool mCustomCursor; /**< Show custom cursor */
ImageSet *mMouseCursors; /**< Mouse cursor images */
float mMouseCursorAlpha;
@@ -118,13 +131,6 @@ extern Gui *gui; /**< The GUI system */
extern SDLInput *guiInput; /**< GUI input */
/**
- * Fonts used in showing hits
- */
-extern gcn::Font *hitRedFont;
-extern gcn::Font *hitBlueFont;
-extern gcn::Font *hitYellowFont;
-
-/**
* Bolded text font
*/
extern gcn::Font *boldFont;
diff --git a/src/gui/help.cpp b/src/gui/help.cpp
index 30c6a9c4..03dfd08d 100644
--- a/src/gui/help.cpp
+++ b/src/gui/help.cpp
@@ -39,16 +39,17 @@ HelpWindow::HelpWindow():
setWindowName("Help");
setResizable(true);
+ setDefaultSize(500, 400, ImageRect::CENTER);
+
mBrowserBox = new BrowserBox;
mBrowserBox->setOpaque(false);
mScrollArea = new ScrollArea(mBrowserBox);
Button *okButton = new Button(_("Close"), "close", this);
- mScrollArea->setDimension(gcn::Rectangle(
- 5, 5, 445, 335 - okButton->getHeight()));
- okButton->setPosition(
- 450 - okButton->getWidth(),
- 345 - okButton->getHeight());
+ mScrollArea->setDimension(gcn::Rectangle(5, 5, 445,
+ 335 - okButton->getHeight()));
+ okButton->setPosition(450 - okButton->getWidth(),
+ 345 - okButton->getHeight());
mBrowserBox->setLinkHandler(this);
@@ -58,7 +59,7 @@ HelpWindow::HelpWindow():
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
- setLocationRelativeTo(getParent());
+ loadWindowState();
}
void HelpWindow::action(const gcn::ActionEvent &event)
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index d18490a4..0b554469 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -24,12 +24,11 @@
#include <guichan/font.hpp>
#include <guichan/mouseinput.hpp>
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "inventorywindow.h"
#include "item_amount.h"
#include "itemcontainer.h"
+#include "label.h"
#include "progressbar.h"
#include "scrollarea.h"
#include "sdlinput.h"
@@ -40,7 +39,6 @@
#include "../inventory.h"
#include "../item.h"
#include "../localplayer.h"
-#include "../log.h"
#include "../units.h"
#include "../resources/iteminfo.h"
@@ -63,7 +61,7 @@ InventoryWindow::InventoryWindow(int invSize):
setMinWidth(375);
setMinHeight(283);
// If you adjust these defaults, don't forget to adjust the trade window's.
- setDefaultSize(115, 30, 375, 283);
+ setDefaultSize(375, 300, ImageRect::CENTER);
addKeyListener(this);
std::string longestUseString = getFont()->getWidth(_("Equip")) >
@@ -96,8 +94,8 @@ InventoryWindow::InventoryWindow(int invSize):
mMaxWeight = -1;
mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed());
- mSlotsLabel = new gcn::Label(_("Slots: "));
- mWeightLabel = new gcn::Label(_("Weight: "));
+ mSlotsLabel = new Label(_("Slots: "));
+ mWeightLabel = new Label(_("Weight: "));
mSlotsBar = new ProgressBar(1.0f, 100, 20, 225, 200, 25);
mWeightBar = new ProgressBar(1.0f, 100, 20, 0, 0, 255);
@@ -129,6 +127,9 @@ InventoryWindow::~InventoryWindow()
void InventoryWindow::logic()
{
+ if (!isVisible())
+ return;
+
Window::logic();
// It would be nicer if this update could be event based, needs some
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index 6a51c66d..95a47bdb 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -22,13 +22,13 @@
#ifndef INVENTORYWINDOW_H
#define INVENTORYWINDOW_H
-#include <guichan/actionlistener.hpp>
-#include <guichan/selectionlistener.hpp>
-#include <guichan/keylistener.hpp>
-
#include "window.h"
-#include "../localplayer.h"
+#include "../inventory.h"
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/keylistener.hpp>
+#include <guichan/selectionlistener.hpp>
class Item;
class ItemContainer;
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index 3bd388f4..0f6aa593 100644
--- a/src/gui/item_amount.cpp
+++ b/src/gui/item_amount.cpp
@@ -20,9 +20,12 @@
*/
#include "button.h"
-#include "inttextfield.h"
#include "item_amount.h"
+#include "label.h"
#include "slider.h"
+#ifdef EATHENA_SUPPORT
+#include "storagewindow.h"
+#endif
#include "trade.h"
#include "widgets/layout.h"
@@ -31,46 +34,54 @@
#include "../localplayer.h"
#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item,
int maxRange):
Window("", true, parent),
- mItem(item)
+ mItem(item),
+ mMax(maxRange),
+ mUsage(usage)
{
- if (!maxRange)
- {
- maxRange = mItem->getQuantity();
- }
+ if (!mMax)
+ mMax = mItem->getQuantity();
+
+ setCloseButton(true);
// Integer field
- mItemAmountTextField = new IntTextField(1);
- mItemAmountTextField->setRange(1, maxRange);
- mItemAmountTextField->setWidth(30);
- mItemAmountTextField->setActionEventId("Dummy");
- mItemAmountTextField->addActionListener(this);
+
+ mItemAmountLabel = new Label(strprintf("%d / %d", 1, mMax));
+ mItemAmountLabel->setAlignment(gcn::Graphics::CENTER);
// Slider
- mItemAmountSlide = new Slider(1.0, maxRange);
+ mItemAmountSlide = new Slider(1.0, mMax);
mItemAmountSlide->setHeight(10);
mItemAmountSlide->setActionEventId("Slide");
mItemAmountSlide->addActionListener(this);
// Buttons
Button *minusButton = new Button("-", "Minus", this);
- minusButton->setSize(20, 20);
Button *plusButton = new Button("+", "Plus", this);
- plusButton->setSize(20, 20);
- Button *okButton = new Button(_("Ok"), "Drop", this);
+ Button *okButton = new Button(_("Ok"), "Ok", this);
Button *cancelButton = new Button(_("Cancel"), "Cancel", this);
+ Button *addAllButton = new Button(_("All"), "All", this);
+
+ minusButton->adjustSize();
+ minusButton->setWidth(plusButton->getWidth());
// Set positions
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+
place(0, 0, minusButton);
- place(1, 0, mItemAmountTextField).setPadding(2);
- place(2, 0, plusButton);
- place(0, 1, mItemAmountSlide, 6);
- place(4, 2, okButton);
- place(5, 2, cancelButton);
- reflowLayout(250, 0);
+ place(1, 0, mItemAmountSlide, 3);
+ place(4, 0, plusButton);
+ place(5, 0, mItemAmountLabel, 2);
+ place(7, 0, addAllButton);
+ place = getPlacer(0, 1);
+ place(4, 0, cancelButton);
+ place(5, 0, okButton);
+ reflowLayout(225, 0);
resetAmount();
@@ -78,15 +89,18 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item,
{
case AMOUNT_TRADE_ADD:
setCaption(_("Select amount of items to trade."));
- okButton->setActionEventId("AddTrade");
break;
case AMOUNT_ITEM_DROP:
setCaption(_("Select amount of items to drop."));
- okButton->setActionEventId("Drop");
+ break;
+ case AMOUNT_STORE_ADD:
+ setCaption(_("Select amount of items to store."));
+ break;
+ case AMOUNT_STORE_REMOVE:
+ setCaption(_("Select amount of items to retrieve."));
break;
case AMOUNT_ITEM_SPLIT:
setCaption(_("Select amount of items to split."));
- okButton->setActionEventId("Split");
break;
default:
break;
@@ -98,22 +112,22 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item,
void ItemAmountWindow::resetAmount()
{
- mItemAmountTextField->setValue(1);
+ mItemAmountLabel->setCaption(strprintf("%d / %d", 1, mMax));
}
void ItemAmountWindow::action(const gcn::ActionEvent &event)
{
- int amount = mItemAmountTextField->getValue();
+ int amount = mItemAmountSlide->getValue();
if (event.getId() == "Cancel")
{
- scheduleDelete();
+ close();
}
- else if (event.getId() == "Plus")
+ else if (event.getId() == "Plus" && amount < mMax)
{
amount++;
}
- else if (event.getId() == "Minus")
+ else if (event.getId() == "Minus" && amount > 1)
{
amount--;
}
@@ -121,23 +135,45 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event)
{
amount = static_cast<int>(mItemAmountSlide->getValue());
}
- else if (event.getId() == "Drop")
- {
- player_node->dropItem(mItem, mItemAmountTextField->getValue());
- scheduleDelete();
- }
- else if (event.getId() == "AddTrade")
+ else if (event.getId() == "Ok" || event.getId() == "All")
{
- tradeWindow->tradeItem(mItem, mItemAmountTextField->getValue());
- scheduleDelete();
- }
+ if (event.getId() == "All")
+ amount = mMax;
+
+ switch (mUsage)
+ {
+ case AMOUNT_TRADE_ADD:
+ tradeWindow->tradeItem(mItem, amount);
+ break;
+ case AMOUNT_ITEM_DROP:
+ player_node->dropItem(mItem, amount);
+ break;
#ifdef TMWSERV_SUPPORT
- else if (event.getId() == "Split")
- {
- player_node->splitItem(mItem, mItemAmountTextField->getValue());
+ case AMOUNT_ITEM_SPLIT:
+ player_node->splitItem(mItem, amount);
+ break;
+#else
+ case AMOUNT_STORE_ADD:
+ storageWindow->addStore(mItem, amount);
+ break;
+ case AMOUNT_STORE_REMOVE:
+ storageWindow->removeStore(mItem, amount);
+ break;
+#endif
+ default:
+ return;
+ break;
+ }
+
scheduleDelete();
+ return;
}
-#endif
- mItemAmountTextField->setValue(amount);
+
+ mItemAmountLabel->setCaption(strprintf("%d / %d", amount, mMax));
mItemAmountSlide->setValue(amount);
}
+
+void ItemAmountWindow::close()
+{
+ scheduleDelete();
+}
diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h
index 4fdb8dc6..344f8c28 100644
--- a/src/gui/item_amount.h
+++ b/src/gui/item_amount.h
@@ -31,7 +31,9 @@ class Item;
#define AMOUNT_TRADE_ADD 1
#define AMOUNT_ITEM_DROP 2
-#define AMOUNT_ITEM_SPLIT 3
+#define AMOUNT_STORE_ADD 3
+#define AMOUNT_STORE_REMOVE 4
+#define AMOUNT_ITEM_SPLIT 5
/**
* Window used for selecting the amount of items to drop, trade or split.
@@ -56,10 +58,17 @@ class ItemAmountWindow : public Window, public gcn::ActionListener
*/
void resetAmount();
+ /**
+ * Schedules the Item Amount window for deletion.
+ */
+ void close();
+
private:
- IntTextField *mItemAmountTextField; /**< Item amount caption. */
+ gcn::Label *mItemAmountLabel; /**< Item amount caption. */
Item *mItem;
+ int mMax, mUsage;
+
/**
* Item Amount buttons.
*/
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index bdae9ada..38a41e0e 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -19,15 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemcontainer.h"
-#include "chat.h"
-
-#include "itempopup.h"
#include <guichan/mouseinput.hpp>
#include <guichan/selectionlistener.hpp>
+#include "chat.h"
+#include "itemcontainer.h"
+#include "itempopup.h"
+#include "palette.h"
#include "sdlinput.h"
+#include "viewport.h"
#include "../graphics.h"
#include "../inventory.h"
@@ -306,12 +307,10 @@ void ItemContainer::mouseMoved(gcn::MouseEvent &event)
if (item)
{
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
-
- mItemPopup->setItem(item->getInfo());
- mItemPopup->setOpaque(false);
- mItemPopup->view(mouseX, mouseY);
+ if (item->getInfo().getName() != mItemPopup->getItemName())
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->updateColors();
+ mItemPopup->view(viewport->getMouseX(), viewport->getMouseY());
}
else
{
diff --git a/src/gui/itemlinkhandler.cpp b/src/gui/itemlinkhandler.cpp
index 4060b303..29fa310d 100644
--- a/src/gui/itemlinkhandler.cpp
+++ b/src/gui/itemlinkhandler.cpp
@@ -22,10 +22,9 @@
#include <sstream>
#include <string>
-#include <SDL_mouse.h>
-
#include "itemlinkhandler.h"
#include "itempopup.h"
+#include "viewport.h"
#include "../resources/iteminfo.h"
#include "../resources/itemdb.h"
@@ -33,6 +32,7 @@
ItemLinkHandler::ItemLinkHandler()
{
mItemPopup = new ItemPopup;
+ mItemPopup->setOpaque(false);
}
ItemLinkHandler::~ItemLinkHandler()
@@ -49,15 +49,18 @@ void ItemLinkHandler::handleLink(const std::string &link)
if (id > 0)
{
const ItemInfo &iteminfo = ItemDB::get(id);
- int mouseX, mouseY;
-
- SDL_GetMouseState(&mouseX, &mouseY);
- mItemPopup->setItem(iteminfo);
+ if (iteminfo.getName() != mItemPopup->getItemName())
+ mItemPopup->setItem(iteminfo);
if (mItemPopup->isVisible())
+ {
mItemPopup->setVisible(false);
+ }
else
- mItemPopup->view(mouseX, mouseY);
+ {
+ mItemPopup->updateColors();
+ mItemPopup->view(viewport->getMouseX(), viewport->getMouseY());
+ }
}
}
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
index 25e6e78e..1b0a2bb2 100644
--- a/src/gui/itempopup.cpp
+++ b/src/gui/itempopup.cpp
@@ -26,11 +26,11 @@
#include "gui.h"
#include "itempopup.h"
+#include "palette.h"
#include "scrollarea.h"
#include "textbox.h"
-#include "windowcontainer.h"
-#include "widgets/layout.h"
+#include "../graphics.h"
#include "../units.h"
@@ -40,14 +40,12 @@
#include "../utils/stringutils.h"
ItemPopup::ItemPopup():
- Window()
+ Popup()
{
- setResizable(false);
- setShowTitle(false);
- setTitleBarHeight(0);
+ mItemType = "";
// Item Name
- mItemName = new gcn::Label("Label");
+ mItemName = new gcn::Label("");
mItemName->setFont(boldFont);
mItemName->setPosition(2, 2);
@@ -88,8 +86,6 @@ ItemPopup::ItemPopup():
add(mItemDescScroll);
add(mItemEffectScroll);
add(mItemWeightScroll);
-
- setLocationRelativeTo(getParent());
}
ItemPopup::~ItemPopup()
@@ -105,15 +101,18 @@ ItemPopup::~ItemPopup()
void ItemPopup::setItem(const ItemInfo &item)
{
+ if (item.getName() == mItemName->getCaption())
+ return;
+
mItemName->setCaption(item.getName());
-#ifdef EATHENA_SUPPORT
- mItemName->setForegroundColor(getColor(item.getType()));
-#endif
mItemName->setWidth(boldFont->getWidth(item.getName()));
mItemDesc->setTextWrapped(item.getDescription(), 196);
mItemEffect->setTextWrapped(item.getEffect(), 196);
mItemWeight->setTextWrapped(_("Weight: ") +
Units::formatWeight(item.getWeight()), 196);
+#ifdef EATHENA_SUPPORT
+ mItemType = item.getType();
+#endif
int minWidth = mItemName->getWidth();
@@ -166,40 +165,53 @@ void ItemPopup::setItem(const ItemInfo &item)
(2 * getFont()->getHeight()));
}
+void ItemPopup::updateColors()
+{
+#ifdef EATHENA_SUPPORT
+ mItemName->setForegroundColor(getColor(mItemType));
+#endif
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+}
+
gcn::Color ItemPopup::getColor(const std::string& type)
{
gcn::Color color;
if (type.compare("generic") == 0)
- color = 0x21a5b1;
+ color = guiPalette->getColor(Palette::GENERIC);
else if (type.compare("equip-head") == 0)
- color = 0x527fa4;
+ color = guiPalette->getColor(Palette::HEAD);
else if (type.compare("usable") == 0)
- color = 0x268d24;
+ color = guiPalette->getColor(Palette::USABLE);
else if (type.compare("equip-torso") == 0)
- color = 0xd12aa4;
+ color = guiPalette->getColor(Palette::TORSO);
else if (type.compare("equip-1hand") == 0)
- color = 0xf42a2a;
+ color = guiPalette->getColor(Palette::ONEHAND);
else if (type.compare("equip-legs") == 0)
- color = 0x699900;
+ color = guiPalette->getColor(Palette::LEGS);
else if (type.compare("equip-feet") == 0)
- color = 0xaa1d48;
+ color = guiPalette->getColor(Palette::FEET);
else if (type.compare("equip-2hand") == 0)
- color = 0xf46d0e;
+ color = guiPalette->getColor(Palette::TWOHAND);
else if (type.compare("equip-shield") == 0)
- color = 0x9c2424;
+ color = guiPalette->getColor(Palette::SHIELD);
else if (type.compare("equip-ring") == 0)
- color = 0x0000ff;
+ color = guiPalette->getColor(Palette::RING);
else if (type.compare("equip-arms") == 0)
- color = 0x9c24e8;
+ color = guiPalette->getColor(Palette::ARMS);
else if (type.compare("equip-ammo") == 0)
- color = 0x8b6311;
+ color = guiPalette->getColor(Palette::AMMO);
else
- color = 0x000000;
+ color = guiPalette->getColor(Palette::UNKNOWN_ITEM);
return color;
}
+std::string ItemPopup::getItemName()
+{
+ return mItemName->getCaption();
+}
+
unsigned int ItemPopup::getNumRows()
{
return mItemDesc->getNumberOfRows() + mItemEffect->getNumberOfRows() +
@@ -208,8 +220,8 @@ unsigned int ItemPopup::getNumRows()
void ItemPopup::view(int x, int y)
{
- if (windowContainer->getWidth() < (x + getWidth() + 5))
- x = windowContainer->getWidth() - getWidth();
+ if (graphics->getWidth() < (x + getWidth() + 5))
+ x = graphics->getWidth() - getWidth();
if ((y - getHeight() - 10) < 0)
y = 0;
else
diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h
index c820e3a0..03e79886 100644
--- a/src/gui/itempopup.h
+++ b/src/gui/itempopup.h
@@ -23,20 +23,48 @@
#ifndef ITEMPOPUP_H
#define ITEMPOPUP_H
-#include "window.h"
+#include "popup.h"
class ItemInfo;
class ScrollArea;
class TextBox;
-class ItemPopup : public Window
+class ItemPopup : public Popup
{
public:
+ /**
+ * Constructor. Initializes the item popup.
+ */
ItemPopup();
+
+ /**
+ * Destructor. Cleans up the item popup on deletion.
+ */
~ItemPopup();
+ /**
+ * Sets the info to be displayed given a particular item.
+ */
void setItem(const ItemInfo &item);
+
+ /**
+ * Gets the number of rows that the item popup currently has.
+ */
unsigned int getNumRows();
+
+ /**
+ * Gets the name of the currently stored item in this popup.
+ */
+ std::string getItemName();
+
+ /**
+ * Updates the colors used within the item popup.
+ */
+ void updateColors();
+
+ /**
+ * Sets the location to display the item popup.
+ */
void view(int x, int y);
private:
@@ -44,6 +72,7 @@ class ItemPopup : public Window
TextBox *mItemDesc;
TextBox *mItemEffect;
TextBox *mItemWeight;
+ std::string mItemType;
ScrollArea *mItemDescScroll;
ScrollArea *mItemEffectScroll;
ScrollArea *mItemWeightScroll;
diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp
index 8864cbd9..45a5ffa0 100644
--- a/src/gui/itemshortcutcontainer.cpp
+++ b/src/gui/itemshortcutcontainer.cpp
@@ -18,10 +18,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <SDL_mouse.h>
+#include "inventorywindow.h"
#include "itemshortcutcontainer.h"
#include "itempopup.h"
+#include "palette.h"
#include "viewport.h"
#include "../configuration.h"
@@ -46,6 +47,7 @@ ItemShortcutContainer::ItemShortcutContainer():
addWidgetListener(this);
mItemPopup = new ItemPopup;
+ mItemPopup->setOpaque(false);
ResourceManager *resman = ResourceManager::getInstance();
@@ -64,24 +66,19 @@ ItemShortcutContainer::~ItemShortcutContainer()
delete mItemPopup;
}
-void ItemShortcutContainer::logic()
+void ItemShortcutContainer::draw(gcn::Graphics *graphics)
{
- gcn::Widget::logic();
-
- int i = itemShortcut->getItemCount();
+ if (!isVisible())
+ return;
- if (i != mMaxItems)
+ if (config.getValue("guialpha", 0.8) != mAlpha)
{
- mMaxItems = i;
- setWidth(getWidth());
+ mAlpha = config.getValue("guialpha", 0.8);
+ mBackgroundImg->setAlpha(mAlpha);
}
-}
-void ItemShortcutContainer::draw(gcn::Graphics *graphics)
-{
Graphics *g = static_cast<Graphics*>(graphics);
- graphics->setColor(gcn::Color(0, 0, 0));
graphics->setFont(getFont());
for (int i = 0; i < mMaxItems; i++)
@@ -94,7 +91,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
// Draw item keyboard shortcut.
const char *key = SDL_GetKeyName(
(SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_1 + i));
- graphics->setColor(0x000000);
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT);
if (itemShortcut->getItem(i) < 0)
@@ -102,6 +99,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
Item *item =
player_node->getInventory()->findItem(itemShortcut->getItem(i));
+
if (item)
{
// Draw item icon.
@@ -115,14 +113,12 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
#endif
toString(item->getQuantity());
g->drawImage(image, itemX, itemY);
- g->drawText(
- label,
- itemX + mBoxWidth / 2,
- itemY + mBoxHeight - 14,
- gcn::Graphics::CENTER);
+ g->drawText(label, itemX + mBoxWidth / 2,
+ itemY + mBoxHeight - 14, gcn::Graphics::CENTER);
}
}
}
+
if (mItemMoved)
{
// Draw the item image being dragged by the cursor.
@@ -133,18 +129,11 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
const int tPosY = mCursorPosY - (image->getHeight() / 2);
g->drawImage(image, tPosX, tPosY);
- g->drawText(
- toString(mItemMoved->getQuantity()),
- tPosX + mBoxWidth / 2,
- tPosY + mBoxHeight - 14,
- gcn::Graphics::CENTER);
+ g->drawText(toString(mItemMoved->getQuantity()),
+ tPosX + mBoxWidth / 2, tPosY + mBoxHeight - 14,
+ gcn::Graphics::CENTER);
}
}
-
- if (config.getValue("guialpha", 0.8) != mAlpha)
- {
- mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8));
- }
}
void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
@@ -156,10 +145,7 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
const int index = getIndexFromGrid(event.getX(), event.getY());
const int itemId = itemShortcut->getItem(index);
- if (index == -1)
- return;
-
- if (itemId < 0)
+ if (index == -1 || itemId < 0)
return;
Item *item = player_node->getInventory()->findItem(itemId);
@@ -170,7 +156,8 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
itemShortcut->removeItem(index);
}
}
- if (mItemMoved) {
+ if (mItemMoved)
+ {
mCursorPosX = event.getX();
mCursorPosY = event.getY();
}
@@ -180,14 +167,14 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event)
{
const int index = getIndexFromGrid(event.getX(), event.getY());
+
if (index == -1)
return;
if (event.getButton() == gcn::MouseEvent::LEFT)
{
-
// Stores the selected item if theirs one.
- if (itemShortcut->isItemSelected())
+ if (itemShortcut->isItemSelected() && inventoryWindow->isVisible())
{
itemShortcut->setItem(index);
itemShortcut->setItemSelected(-1);
@@ -203,12 +190,9 @@ void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event)
if (!item)
return;
- /* Convert relative to the window coordinates to absolute screen
- * coordinates.
- */
- int mx, my;
- SDL_GetMouseState(&mx, &my);
- viewport->showPopup(mx, my, item);
+ // Convert relative to the window coordinates to absolute screen
+ // coordinates.
+ viewport->showPopup(viewport->getMouseX(), viewport->getMouseY(), item);
}
}
@@ -234,6 +218,7 @@ void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event)
{
itemShortcut->useItem(index);
}
+
if (mItemClicked)
mItemClicked = false;
}
@@ -245,22 +230,17 @@ void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event)
const int index = getIndexFromGrid(event.getX(), event.getY());
const int itemId = itemShortcut->getItem(index);
- if (index == -1)
- return;
-
- if (itemId < 0)
+ if (index == -1 || itemId < 0)
return;
Item *item = player_node->getInventory()->findItem(itemId);
- if (item)
+ if (item && inventoryWindow->isVisible())
{
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
-
- mItemPopup->setItem(item->getInfo());
- mItemPopup->setOpaque(false);
- mItemPopup->view(mouseX, mouseY);
+ if (item->getInfo().getName() != mItemPopup->getItemName())
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->updateColors();
+ mItemPopup->view(viewport->getMouseX(), viewport->getMouseY());
}
else
{
diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h
index 22d94ec2..9d188bf0 100644
--- a/src/gui/itemshortcutcontainer.h
+++ b/src/gui/itemshortcutcontainer.h
@@ -49,11 +49,6 @@ class ItemShortcutContainer : public ShortcutContainer
virtual ~ItemShortcutContainer();
/**
- * Handles the logic of the ItemContainer
- */
- void logic();
-
- /**
* Draws the items.
*/
void draw(gcn::Graphics *graphics);
diff --git a/src/gui/label.cpp b/src/gui/label.cpp
new file mode 100644
index 00000000..e8d72ace
--- /dev/null
+++ b/src/gui/label.cpp
@@ -0,0 +1,40 @@
+/*
+ * Aethyra
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ * Copyright (c) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra based on original code
+ * from GUIChan.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "label.h"
+#include "palette.h"
+
+Label::Label() :
+ gcn::Label()
+{
+}
+
+Label::Label(const std::string& caption) :
+ gcn::Label(caption)
+{
+}
+
+void Label::draw(gcn::Graphics* graphics)
+{
+ setForegroundColor(guiPalette->getColor(Palette::TEXT));
+ gcn::Label::draw(static_cast<gcn::Graphics*>(graphics));
+}
diff --git a/src/gui/label.h b/src/gui/label.h
new file mode 100644
index 00000000..961286e0
--- /dev/null
+++ b/src/gui/label.h
@@ -0,0 +1,55 @@
+/*
+ * Aethyra
+ * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
+ * Copyright (c) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra based on original code
+ * from GUIChan.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LABEL_H
+#define LABEL_H
+
+#include <guichan/widgets/label.hpp>
+
+/**
+ * Label widget. Same as the Guichan label but modified to use the palette
+ * system.
+ *
+ * \ingroup GUI
+ */
+class Label : public gcn::Label
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Label();
+
+ /**
+ * Constructor. This version of the constructor sets the label with an
+ * inintialization string.
+ */
+ Label(const std::string& caption);
+
+ /**
+ * Draws the label.
+ */
+ void draw(gcn::Graphics* graphics);
+};
+
+#endif
diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp
index 74d0b9ad..7ba84ee7 100644
--- a/src/gui/listbox.cpp
+++ b/src/gui/listbox.cpp
@@ -21,10 +21,11 @@
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
+#include <guichan/key.hpp>
#include <guichan/listmodel.hpp>
-#include "color.h"
#include "listbox.h"
+#include "palette.h"
#include "../configuration.h"
@@ -37,30 +38,25 @@ ListBox::ListBox(gcn::ListModel *listModel):
void ListBox::draw(gcn::Graphics *graphics)
{
- if (!mListModel)
+ if (!mListModel || !isVisible())
return;
if (config.getValue("guialpha", 0.8) != mAlpha)
mAlpha = config.getValue("guialpha", 0.8);
- bool valid;
- const int red = (textColor->getColor('H', valid) >> 16) & 0xFF;
- const int green = (textColor->getColor('H', valid) >> 8) & 0xFF;
- const int blue = textColor->getColor('H', valid) & 0xFF;
- const int alpha = (int)(mAlpha * 255.0f);
-
- graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT,
+ (int)(mAlpha * 255.0f)));
graphics->setFont(getFont());
const int fontHeight = getFont()->getHeight();
- // Draw rectangle below the selected list element
+ // Draw filled rectangle around the selected list element
if (mSelected >= 0)
graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
getWidth(), fontHeight));
// Draw the list elements
- graphics->setColor(gcn::Color(0, 0, 0, 255));
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
for (int i = 0, y = 0; i < mListModel->getNumberOfElements();
++i, y += fontHeight)
{
@@ -68,6 +64,91 @@ void ListBox::draw(gcn::Graphics *graphics)
}
}
+void ListBox::setSelected(int selected)
+{
+ if (!mListModel)
+ {
+ mSelected = -1;
+ }
+ else
+ {
+ if (selected < 0 && !mWrappingEnabled)
+ {
+ mSelected = -1;
+ }
+ else if (selected >= mListModel->getNumberOfElements() &&
+ mWrappingEnabled)
+ {
+ mSelected = 0;
+ }
+ else if ((selected >= mListModel->getNumberOfElements() &&
+ !mWrappingEnabled) || (selected < 0 && mWrappingEnabled))
+ {
+ mSelected = mListModel->getNumberOfElements() - 1;
+ }
+ else
+ {
+ mSelected = selected;
+ }
+ }
+ gcn::ListBox::setSelected(mSelected);
+}
+
+// -- KeyListener notifications
+void ListBox::keyPressed(gcn::KeyEvent& keyEvent)
+{
+ gcn::Key key = keyEvent.getKey();
+
+ if (key.getValue() == gcn::Key::ENTER || key.getValue() == gcn::Key::SPACE)
+ {
+ distributeActionEvent();
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::UP)
+ {
+ setSelected(mSelected - 1);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::DOWN)
+ {
+ setSelected(mSelected + 1);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::HOME)
+ {
+ setSelected(0);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::END)
+ {
+ setSelected(getListModel()->getNumberOfElements() - 1);
+ keyEvent.consume();
+ }
+}
+
+void ListBox::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
+{
+ if (isFocused())
+ {
+ if (getSelected() > 0 || (getSelected() == 0 && mWrappingEnabled))
+ {
+ setSelected(getSelected() - 1);
+ }
+
+ mouseEvent.consume();
+ }
+}
+
+void ListBox::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
+{
+ if (isFocused())
+ {
+ setSelected(getSelected() + 1);
+
+ mouseEvent.consume();
+ }
+}
+
void ListBox::mouseDragged(gcn::MouseEvent &event)
{
// Pretend mouse is pressed continuously while dragged. Causes list
diff --git a/src/gui/listbox.h b/src/gui/listbox.h
index 12fcb955..cfb58f15 100644
--- a/src/gui/listbox.h
+++ b/src/gui/listbox.h
@@ -46,8 +46,27 @@ class ListBox : public gcn::ListBox
*/
void draw(gcn::Graphics *graphics);
+ // Inherited from KeyListener
+
+ void keyPressed(gcn::KeyEvent& keyEvent);
+
+ // Inherited from MouseListener
+
+ void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent);
+
+ void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent);
+
void mouseDragged(gcn::MouseEvent &event);
+ /**
+ * Sets the selected item. The selected item is represented by
+ * an index from the list model.
+ *
+ * @param selected the selected item as an index from the list model.
+ * @see getSelected
+ */
+ void setSelected(int selected);
+
private:
static float mAlpha;
};
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index e68a8da1..281a25a2 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "checkbox.h"
+#include "label.h"
#include "listbox.h"
#include "login.h"
#include "ok_dialog.h"
@@ -48,12 +47,12 @@ static const int FIELD_WIDTH = LOGIN_DIALOG_WIDTH - 70;
LoginDialog::LoginDialog(LoginData *loginData):
Window(_("Login")), mLoginData(loginData)
{
- gcn::Label *userLabel = new gcn::Label(_("Name:"));
- gcn::Label *passLabel = new gcn::Label(_("Password:"));
+ gcn::Label *userLabel = new Label(_("Name:"));
+ gcn::Label *passLabel = new Label(_("Password:"));
#ifdef EATHENA_SUPPORT
- gcn::Label *serverLabel = new gcn::Label(_("Server:"));
- gcn::Label *portLabel = new gcn::Label(_("Port:"));
- gcn::Label *dropdownLabel = new gcn::Label(_("Recent:"));
+ gcn::Label *serverLabel = new Label(_("Server:"));
+ gcn::Label *portLabel = new Label(_("Port:"));
+ gcn::Label *dropdownLabel = new Label(_("Recent:"));
std::vector<std::string> dfltServer;
dfltServer.push_back("server.themanaworld.org");
std::vector<std::string> dfltPort;
@@ -124,14 +123,13 @@ LoginDialog::LoginDialog(LoginData *loginData):
place(3, 6, mOkButton);
reflowLayout(250, 0);
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
- if (mUserField->getText().empty()) {
+ if (mUserField->getText().empty())
mUserField->requestFocus();
- } else {
+ else
mPassField->requestFocus();
- }
mOkButton->setEnabled(canSubmit());
}
@@ -179,15 +177,13 @@ void LoginDialog::action(const gcn::ActionEvent &event)
#ifdef EATHENA_SUPPORT
// Transfer these fields on to the register dialog
mLoginData->hostname = mServerField->getText();
+
if (isUShort(mPortField->getText()))
- {
mLoginData->port = getUShort(mPortField->getText());
- }
else
- {
mLoginData->port = 6901;
- }
#endif
+
mLoginData->username = mUserField->getText();
mLoginData->password = mPassField->getText();
@@ -223,14 +219,12 @@ bool LoginDialog::isUShort(const std::string &str)
strPtr != strEnd; ++strPtr)
{
if (*strPtr < '0' || *strPtr > '9')
- {
return false;
- }
+
l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative
+
if (l > 65535)
- {
return false;
- }
}
return true;
}
@@ -306,9 +300,7 @@ void LoginDialog::DropDownList::save(const std::string &server,
++sPtr, ++pPtr)
{
if (*sPtr != server || *pPtr != port)
- {
saveEntry(*sPtr, *pPtr, position);
- }
}
}
@@ -320,27 +312,24 @@ int LoginDialog::DropDownList::getNumberOfElements()
std::string LoginDialog::DropDownList::getElementAt(int i)
{
if (i < 0 || i >= getNumberOfElements())
- {
- return "";
- }
+ return "";
+
return getServerAt(i) + ":" + getPortAt(i);
}
std::string LoginDialog::DropDownList::getServerAt(int i)
{
if (i < 0 || i >= getNumberOfElements())
- {
return "";
- }
+
return mServers.at(i);
}
std::string LoginDialog::DropDownList::getPortAt(int i)
{
if (i < 0 || i >= getNumberOfElements())
- {
return "";
- }
+
return mPorts.at(i);
}
#endif
diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp
index 25ece461..e6ae2d3b 100644
--- a/src/gui/menuwindow.cpp
+++ b/src/gui/menuwindow.cpp
@@ -25,7 +25,9 @@
#include "button.h"
#include "menuwindow.h"
-#include "windowcontainer.h"
+#include "window.h"
+
+#include "../graphics.h"
#include "../utils/gettext.h"
@@ -54,13 +56,8 @@ namespace {
}
MenuWindow::MenuWindow():
- Window()
+ Popup("Menu")
{
- setResizable(false);
- setWindowName("Menu");
- setMovable(false);
- setTitleBarHeight(0);
-
// Buttons
static const char *buttonNames[] =
{
@@ -90,7 +87,7 @@ MenuWindow::MenuWindow():
h = btn->getHeight();
}
- setPosition(windowContainer->getWidth() - x - 3, 3);
+ setPosition(graphics->getWidth() - x - 3, 3);
setContentSize(x - 3, h);
}
@@ -99,7 +96,6 @@ void MenuWindow::draw(gcn::Graphics *graphics)
drawChildren(graphics);
}
-
void MenuWindowListener::action(const gcn::ActionEvent &event)
{
Window *window = NULL;
diff --git a/src/gui/menuwindow.h b/src/gui/menuwindow.h
index 9bb54e29..c3d5673e 100644
--- a/src/gui/menuwindow.h
+++ b/src/gui/menuwindow.h
@@ -22,14 +22,14 @@
#ifndef MENU_H
#define MENU_H
-#include "window.h"
+#include "popup.h"
/**
* The Button Menu.
*
* \ingroup Interface
*/
-class MenuWindow : public Window
+class MenuWindow : public Popup
{
public:
/**
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index 4347c9cc..93a55688 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -79,19 +79,6 @@ void Minimap::setMapImage(Image *img)
mMapImage->getWidth() + offsetX : titleWidth);
setMaxHeight(mMapImage->getHeight() + offsetY);
- // Make sure the window is within the minimum and maximum boundaries
- // TODO: Shouldn't this be happening automatically within the Window
- // class?
- if (getMinWidth() > getWidth())
- setWidth(getMinWidth());
- else if (getMaxWidth() < getWidth())
- setWidth(getMaxWidth());
- if (getMinHeight() > getHeight())
- setHeight(getMinHeight());
- else if (getMaxHeight() < getHeight())
- setHeight(getMaxHeight());
-
- setContentSize(getWidth() - offsetX, getHeight() - offsetY);
setDefaultSize(getX(), getY(), getWidth(), getHeight());
resetToDefaultSize();
@@ -112,6 +99,9 @@ void Minimap::draw(gcn::Graphics *graphics)
{
setVisible(mShow);
+ if (!isVisible())
+ return;
+
Window::draw(graphics);
if (!mShow)
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index 5bc25bdb..95577e69 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -22,6 +22,7 @@
#include "gui.h"
#include "ministatus.h"
#include "progressbar.h"
+#include "status.h"
#include "../animatedsprite.h"
#include "../configuration.h"
@@ -30,13 +31,9 @@
#include "../utils/stringutils.h"
-MiniStatusWindow::MiniStatusWindow()
+MiniStatusWindow::MiniStatusWindow():
+ Popup("MiniStatus")
{
- setWindowName("MiniStatus");
- setResizable(false);
- setMovable(false);
- setTitleBarHeight(0);
-
mHpBar = new ProgressBar(1.0f, 100, 20, 0, 171, 34);
#ifdef EATHENA_SUPPORT
mMpBar = new ProgressBar(1.0f, 100, 20, 26, 102, 230);
@@ -62,8 +59,6 @@ MiniStatusWindow::MiniStatusWindow()
setContentSize(mHpBar->getX() + mHpBar->getWidth(),
mHpBar->getY() + mHpBar->getHeight());
#endif
- setDefaultSize(0, 0, getWidth(), getHeight());
- loadWindowState();
}
void MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite)
@@ -86,43 +81,10 @@ extern volatile int tick_time;
void MiniStatusWindow::update()
{
- // HP Bar coloration
- int maxHp = player_node->getMaxHp();
- int hp = player_node->getHp();
- if (hp < int(maxHp / 3))
- {
- mHpBar->setColor(223, 32, 32); // Red
- }
- else if (hp < int((maxHp / 3) * 2))
- {
- mHpBar->setColor(230, 171, 34); // Orange
- }
- else
- {
- mHpBar->setColor(0, 171, 34); // Green
- }
-
+ StatusWindow::updateHPBar(mHpBar);
#ifdef EATHENA_SUPPORT
- float xp = (float) player_node->getXp() / player_node->mXpForNextLevel;
-
- if (xp != xp) xp = 0.0f; // check for NaN
- if (xp < 0.0f) xp = 0.0f; // make sure the experience isn't negative (uninitialized pointer most likely)
- if (xp > 1.0f) xp = 1.0f;
-#endif
-
- mHpBar->setProgress((float) hp / maxHp);
-#ifdef EATHENA_SUPPORT
- mMpBar->setProgress((float) player_node->mMp / player_node->mMaxMp);
- mXpBar->setProgress(xp);
-#endif
-
- // Update labels
- mHpBar->setText(toString(player_node->getHp()));
-#ifdef EATHENA_SUPPORT
- mMpBar->setText(toString(player_node->mMp));
-
- std::stringstream updatedText;
- updatedText << (float) ((int) (xp * 10000.0f)) / 100.0f << "%";
+ StatusWindow::updateMPBar(mMpBar);
+ StatusWindow::updateXPBar(mXpBar);
// Displays the number of monsters to next lvl
// (disabled for now but interesting idea)
@@ -136,8 +98,6 @@ void MiniStatusWindow::update()
<< config.getValue("xpBarMonsterCounterName", "Monsters") <<" left...";
}
*/
-
- mXpBar->setText(updatedText.str());
#endif
for (unsigned int i = 0; i < mIcons.size(); i++)
diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h
index b69f9a14..f6d80ca7 100644
--- a/src/gui/ministatus.h
+++ b/src/gui/ministatus.h
@@ -22,7 +22,7 @@
#ifndef MINISTATUS_H
#define MINISTATUS_H
-#include "window.h"
+#include "popup.h"
#include <vector>
@@ -34,7 +34,7 @@ class ProgressBar;
*
* \ingroup Interface
*/
-class MiniStatusWindow : public Window
+class MiniStatusWindow : public Popup
{
public:
/**
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 48f2adb7..5158e966 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -28,18 +28,33 @@
#include "../npc.h"
+#include "../net/messageout.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../net/ea/protocol.h"
+#endif
+
#include "../utils/gettext.h"
-NpcTextDialog::NpcTextDialog():
- Window(_("NPC")),
- mState(NPC_TEXT_STATE_WAITING)
+#ifdef TMWSERV_SUPPORT
+NpcTextDialog::NpcTextDialog()
+#else
+NpcTextDialog::NpcTextDialog(Network *network)
+#endif
+ : Window(_("NPC"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
+ , mState(NPC_TEXT_STATE_WAITING)
{
+ setWindowName("NPCText");
setResizable(true);
setMinWidth(200);
setMinHeight(150);
- setDefaultSize(0, 0, 260, 200);
+ setDefaultSize(260, 200, ImageRect::CENTER);
mTextBox = new TextBox;
mTextBox->setEditable(false);
@@ -57,8 +72,14 @@ NpcTextDialog::NpcTextDialog():
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
+ center();
loadWindowState();
- setLocationRelativeTo(getParent());
+}
+
+void NpcTextDialog::clearText()
+{
+ NPC::isTalking = false;
+ setText("");
}
void NpcTextDialog::setText(const std::string &text)
@@ -92,13 +113,15 @@ void NpcTextDialog::action(const gcn::ActionEvent &event)
if (event.getId() == "ok")
{
if (mState == NPC_TEXT_STATE_NEXT && current_npc) {
- current_npc->nextDialog();
+ nextDialog();
addText("\n> Next\n");
} else if (mState == NPC_TEXT_STATE_CLOSE ||
(mState == NPC_TEXT_STATE_NEXT && !current_npc)) {
setText("");
+ if (current_npc) nextDialog();
setVisible(false);
- if (current_npc) current_npc->handleDeath();
+ current_npc = 0;
+ NPC::isTalking = false;
} else return;
}
else return;
@@ -108,6 +131,26 @@ void NpcTextDialog::action(const gcn::ActionEvent &event)
mState = NPC_TEXT_STATE_WAITING;
}
+void NpcTextDialog::nextDialog(int npcID)
+{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::talkToNPC(npcID, false);
+#else
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST);
+ outMsg.writeInt32(npcID);
+#endif
+}
+
+void NpcTextDialog::closeDialog(int npcID)
+{
+#ifdef EATHENA_SUPPORT
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_CLOSE);
+ outMsg.writeInt32(npcID);
+#endif
+}
+
void NpcTextDialog::widgetResized(const gcn::Event &event)
{
Window::widgetResized(event);
@@ -115,3 +158,8 @@ void NpcTextDialog::widgetResized(const gcn::Event &event)
setText(mText);
}
+void NpcTextDialog::requestFocus()
+{
+ loadWindowState();
+ setVisible(true);
+}
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index a1373830..4c0c31e3 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -28,6 +28,11 @@
#include "window.h"
+#include "../npc.h"
+
+#ifdef EATHENA_SUPPORT
+class Network;
+#endif
class TextBox;
/**
@@ -43,7 +48,11 @@ class NpcTextDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
NpcTextDialog();
+#else
+ NpcTextDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -75,6 +84,23 @@ class NpcTextDialog : public Window, public gcn::ActionListener
void showCloseButton();
/**
+ * Notifies the server that the client has performed a next action.
+ */
+ void nextDialog(int npcID = current_npc);
+
+ /**
+ * Notifies the server that the client has performed a close action.
+ */
+ void closeDialog(int npcID = current_npc);
+
+ /**
+ * Initializes window width to the last known setting. Since the dialog
+ * doesn't need any extra focus outside of what it's given in the Game
+ * class, this is all it does for now.
+ */
+ void requestFocus();
+
+ /**
* Called when resizing the window.
*
* @param event The calling event
@@ -82,6 +108,9 @@ class NpcTextDialog : public Window, public gcn::ActionListener
void widgetResized(const gcn::Event &event);
private:
+#ifdef EATHENA_SUPPORT
+ Network *mNetwork;
+#endif
gcn::ScrollArea *mScrollArea;
TextBox *mTextBox;
gcn::Button *mButton;
@@ -93,7 +122,9 @@ class NpcTextDialog : public Window, public gcn::ActionListener
NPC_TEXT_STATE_NEXT,
NPC_TEXT_STATE_CLOSE
};
- int mState;
+ NPCTextState mState;
};
+extern NpcTextDialog *npcTextDialog;
+
#endif // NPC_TEXT_H
diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp
index 463f46ae..a7ae2748 100644
--- a/src/gui/npcintegerdialog.cpp
+++ b/src/gui/npcintegerdialog.cpp
@@ -28,24 +28,37 @@
#include "../npc.h"
+#include "../net/messageout.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-extern NpcTextDialog *npcTextDialog;
-
-NpcIntegerDialog::NpcIntegerDialog():
- Window(_("NPC Number Request"))
+#ifdef TMWSERV_SUPPORT
+NpcIntegerDialog::NpcIntegerDialog()
+#else
+NpcIntegerDialog::NpcIntegerDialog(Network *network)
+#endif
+ : Window(_("NPC Number Request"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
+ setWindowName("NPCInteger");
mValueField = new IntTextField;
+ setDefaultSize(175, 75, ImageRect::CENTER);
+
mDecButton = new Button("-", "decvalue", this);
mIncButton = new Button("+", "incvalue", this);
gcn::Button *okButton = new Button(_("OK"), "ok", this);
gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this);
gcn::Button *resetButton = new Button(_("Reset"), "reset", this);
- mDecButton->setSize(20, 20);
- mIncButton->setSize(20, 20);
+ mDecButton->adjustSize();
+ mDecButton->setWidth(mIncButton->getWidth());
ContainerPlacer place;
place = getPlacer(0, 0);
@@ -60,7 +73,9 @@ NpcIntegerDialog::NpcIntegerDialog():
place(3, 0, okButton);
reflowLayout(175, 0);
- setLocationRelativeTo(getParent());
+ center();
+ setDefaultSize();
+ loadWindowState();
}
void NpcIntegerDialog::setRange(int min, int max)
@@ -73,18 +88,23 @@ int NpcIntegerDialog::getValue()
return mValueField->getValue();
}
+void NpcIntegerDialog::reset()
+{
+ mValueField->reset();
+}
+
void NpcIntegerDialog::action(const gcn::ActionEvent &event)
{
- int finish = 0;
+ bool finish = false;
if (event.getId() == "ok")
{
- finish = 1;
+ finish = true;
npcTextDialog->addText(strprintf("\n> %d\n", mValueField->getValue()));
}
else if (event.getId() == "cancel")
{
- finish = 1;
+ finish = true;
mValueField->reset();
npcTextDialog->addText(_("\n> Cancel\n"));
}
@@ -104,7 +124,15 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event)
if (finish)
{
setVisible(false);
- current_npc->integerInput(mValueField->getValue());
+ NPC::isTalking = false;
+
+#ifdef EATHENA_SUPPORT
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_INT_RESPONSE);
+ outMsg.writeInt32(current_npc);
+ outMsg.writeInt32(mValueField->getValue());
+#endif
+
mValueField->reset();
}
}
@@ -123,3 +151,13 @@ void NpcIntegerDialog::requestFocus()
{
mValueField->requestFocus();
}
+
+void NpcIntegerDialog::setVisible(bool visible)
+{
+ if (visible) {
+ npcTextDialog->setVisible(true);
+ requestFocus();
+ }
+
+ Window::setVisible(visible);
+}
diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h
index 941bb55a..df74c904 100644
--- a/src/gui/npcintegerdialog.h
+++ b/src/gui/npcintegerdialog.h
@@ -26,6 +26,9 @@
#include "window.h"
+#ifdef EATHENA_SUPPORT
+class Network;
+#endif
class IntTextField;
/**
@@ -41,7 +44,11 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
NpcIntegerDialog();
+#else
+ NpcIntegerDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -54,6 +61,11 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener
int getValue();
/**
+ * Resets the integer input field.
+ */
+ void reset();
+
+ /**
* Prepares the NPC dialog.
*
* @param min The minimum value to allow
@@ -78,10 +90,17 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener
*/
void requestFocus();
+ void setVisible(bool visible);
+
private:
+#ifdef EATHENA_SUPPORT
+ Network *mNetwork;
+#endif
gcn::Button *mDecButton;
gcn::Button *mIncButton;
IntTextField *mValueField;
};
+extern NpcIntegerDialog *npcIntegerDialog;
+
#endif // GUI_NPCINTEGERDIALOG_H
diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp
index 82e05fd5..968e2514 100644
--- a/src/gui/npclistdialog.cpp
+++ b/src/gui/npclistdialog.cpp
@@ -31,24 +31,39 @@
#include "../npc.h"
+#include "../net/messageout.h"
+#ifdef TMWSERV_SUPPORT
+#include "../net/tmwserv/gameserver/player.h"
+#else
+#include "../net/ea/protocol.h"
+#endif
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-extern NpcTextDialog *npcTextDialog;
-
-NpcListDialog::NpcListDialog():
- Window(_("NPC"))
+#ifdef TMWSERV_SUPPORT
+NpcListDialog::NpcListDialog()
+#else
+NpcListDialog::NpcListDialog(Network *network)
+#endif
+ : Window("NPC")
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
+ setWindowName("NPCList");
setResizable(true);
setMinWidth(200);
setMinHeight(150);
- setDefaultSize(0, 0, 260, 200);
+ setDefaultSize(260, 200, ImageRect::CENTER);
mItemList = new ListBox(this);
mItemList->setWrappingEnabled(true);
+
gcn::ScrollArea *scrollArea = new ScrollArea(mItemList);
+
gcn::Button *okButton = new Button(_("OK"), "ok", this);
gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this);
@@ -56,14 +71,14 @@ NpcListDialog::NpcListDialog():
scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
place(0, 0, scrollArea, 5).setPadding(3);
- place(3, 1, okButton);
- place(4, 1, cancelButton);
+ place(3, 1, cancelButton);
+ place(4, 1, okButton);
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
+ center();
loadWindowState();
- setLocationRelativeTo(getParent());
}
int NpcListDialog::getNumberOfElements()
@@ -92,6 +107,8 @@ void NpcListDialog::parseItems(const std::string &itemString)
void NpcListDialog::reset()
{
+ NPC::isTalking = false;
+ mItemList->setSelected(-1);
mItems.clear();
}
@@ -102,6 +119,7 @@ void NpcListDialog::action(const gcn::ActionEvent &event)
{
// Send the selected index back to the server
int selectedIndex = mItemList->getSelected();
+
if (selectedIndex > -1)
{
choice = selectedIndex + 1;
@@ -113,12 +131,40 @@ void NpcListDialog::action(const gcn::ActionEvent &event)
{
choice = 0xff; // 0xff means cancel
npcTextDialog->addText(_("\n> Cancel\n"));
+ npcTextDialog->showCloseButton();
}
if (choice)
{
setVisible(false);
+ saveWindowState();
reset();
- current_npc->dialogChoice(choice);
+
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::selectFromNPC(current_npc, choice);
+#else
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_LIST_CHOICE);
+ outMsg.writeInt32(current_npc);
+ outMsg.writeInt8(choice);
+#endif
}
}
+
+void NpcListDialog::setVisible(bool visible)
+{
+ if (visible) {
+ npcTextDialog->setVisible(true);
+ requestFocus();
+ }
+
+ Window::setVisible(visible);
+}
+
+void NpcListDialog::requestFocus()
+{
+ mItemList->requestFocus();
+ mItemList->setSelected(0);
+ loadWindowState();
+ setVisible(true);
+}
diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h
index 7e37c7e6..6c1e02e3 100644
--- a/src/gui/npclistdialog.h
+++ b/src/gui/npclistdialog.h
@@ -29,6 +29,10 @@
#include <vector>
+#ifdef EATHENA_SUPPORT
+class Network;
+#endif
+
/**
* The npc list dialog.
*
@@ -43,7 +47,11 @@ class NpcListDialog : public Window, public gcn::ActionListener,
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
NpcListDialog();
+#else
+ NpcListDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -77,10 +85,23 @@ class NpcListDialog : public Window, public gcn::ActionListener,
*/
void reset();
+ void setVisible(bool visible);
+
+ /**
+ * Requests the listbox to take focus for input and sets window width
+ * to the last known setting.
+ */
+ void requestFocus();
+
private:
+#ifdef EATHENA_SUPPORT
+ Network *mNetwork;
+#endif
gcn::ListBox *mItemList;
std::vector<std::string> mItems;
};
+extern NpcListDialog *npcListDialog;
+
#endif // GUI_NPCLISTDIALOG_H
diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp
index d9bf5682..c84de015 100644
--- a/src/gui/npcstringdialog.cpp
+++ b/src/gui/npcstringdialog.cpp
@@ -28,16 +28,29 @@
#include "../npc.h"
+#include "../net/messageout.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
-extern NpcTextDialog *npcTextDialog;
-
-NpcStringDialog::NpcStringDialog():
- Window(_("NPC Text Request"))
+#ifdef TMWSERV_SUPPORT
+NpcStringDialog::NpcStringDialog()
+#else
+NpcStringDialog::NpcStringDialog(Network *network)
+#endif
+ : Window(_("NPC Text Request"))
+#ifdef EATHENA_SUPPORT
+ , mNetwork(network)
+#endif
{
+ setWindowName("NPCString");
mValueField = new TextField("");
+ setDefaultSize(175, 75, ImageRect::CENTER);
+
gcn::Button *okButton = new Button(_("OK"), "ok", this);
gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this);
@@ -46,7 +59,9 @@ NpcStringDialog::NpcStringDialog():
place(2, 1, okButton);
reflowLayout(175, 0);
- setLocationRelativeTo(getParent());
+ center();
+ setDefaultSize();
+ loadWindowState();
}
std::string NpcStringDialog::getValue()
@@ -74,8 +89,19 @@ void NpcStringDialog::action(const gcn::ActionEvent &event)
}
setVisible(false);
- current_npc->stringInput(mValueField->getText());
+ NPC::isTalking = false;
+
+ std::string text = mValueField->getText();
mValueField->setText("");
+
+#ifdef EATHENA_SUPPORT
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_NPC_STR_RESPONSE);
+ outMsg.writeInt16(text.length() + 9);
+ outMsg.writeInt32(current_npc);
+ outMsg.writeString(text, text.length());
+ outMsg.writeInt8(0);
+#endif
}
bool NpcStringDialog::isInputFocused()
@@ -87,3 +113,13 @@ void NpcStringDialog::requestFocus()
{
mValueField->requestFocus();
}
+
+void NpcStringDialog::setVisible(bool visible)
+{
+ if (visible) {
+ npcTextDialog->setVisible(true);
+ requestFocus();
+ }
+
+ Window::setVisible(visible);
+}
diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h
index 0faaf203..94cd59b2 100644
--- a/src/gui/npcstringdialog.h
+++ b/src/gui/npcstringdialog.h
@@ -26,6 +26,10 @@
#include <guichan/actionlistener.hpp>
+#ifdef EATHENA_SUPPORT
+class Network;
+#endif
+
/**
* The npc integer input dialog.
*
@@ -39,7 +43,11 @@ class NpcStringDialog : public Window, public gcn::ActionListener
*
* @see Window::Window
*/
+#ifdef TMWSERV_SUPPORT
NpcStringDialog();
+#else
+ NpcStringDialog(Network *network);
+#endif
/**
* Called when receiving actions from the widgets.
@@ -68,9 +76,16 @@ class NpcStringDialog : public Window, public gcn::ActionListener
*/
void requestFocus();
+ void setVisible(bool visible);
+
private:
+#ifdef EATHENA_SUPPORT
+ Network *mNetwork;
+#endif
gcn::TextField *mValueField;
std::string mDefault;
};
+extern NpcStringDialog *npcStringDialog;
+
#endif // GUI_NPCSTRINGDIALOG_H
diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp
index 4df3fa07..f1a97b49 100644
--- a/src/gui/ok_dialog.cpp
+++ b/src/gui/ok_dialog.cpp
@@ -22,6 +22,7 @@
#include <guichan/font.hpp>
#include "button.h"
+#include "gui.h"
#include "ok_dialog.h"
#include "scrollarea.h"
#include "textbox.h"
@@ -46,14 +47,15 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg,
mTextBox->setTextWrapped(msg, 260);
int numRows = mTextBox->getNumberOfRows();
+ const int fontHeight = getFont()->getHeight();
if (numRows > 1)
{
- // 15 == height of each line of text (based on font heights)
// 14 == row top + bottom graphic pixel heights
- setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + okButton->getHeight());
- mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
- 3 + (numRows * 14)));
+ setContentSize(mTextBox->getMinWidth() + fontHeight, ((numRows + 1) *
+ fontHeight) + okButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5,
+ mTextBox->getMinWidth() + 5, 3 + (numRows * fontHeight)));
}
else
{
@@ -62,17 +64,17 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg,
width = getFont()->getWidth(msg);
if (width < okButton->getWidth())
width = okButton->getWidth();
- setContentSize(width + 15, 30 + okButton->getHeight());
+ setContentSize(width + fontHeight, 30 + okButton->getHeight());
mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
}
okButton->setPosition((mTextBox->getMinWidth() - okButton->getWidth()) / 2,
- (numRows * 14) + okButton->getHeight() - 8);
+ ((numRows - 1) * fontHeight) + okButton->getHeight() + 2);
add(mTextArea);
add(okButton);
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
okButton->requestFocus();
}
@@ -92,7 +94,6 @@ void OkDialog::action(const gcn::ActionEvent &event)
}
// Can we receive anything else anyway?
- if (event.getId() == "ok") {
+ if (event.getId() == "ok")
scheduleDelete();
- }
}
diff --git a/src/gui/palette.cpp b/src/gui/palette.cpp
new file mode 100644
index 00000000..b1e165aa
--- /dev/null
+++ b/src/gui/palette.cpp
@@ -0,0 +1,347 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ * Copyright (C) 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <math.h>
+
+#include "palette.h"
+#include "gui.h"
+
+#include "../configuration.h"
+#include "../game.h"
+
+#include "../utils/gettext.h"
+#include "../utils/stringutils.h"
+
+const gcn::Color Palette::BLACK = gcn::Color(0, 0, 0);
+
+const gcn::Color Palette::RAINBOW_COLORS[7] = {
+ gcn::Color(255, 0, 0),
+ gcn::Color(255, 153, 0),
+ gcn::Color(255, 255, 0),
+ gcn::Color(0, 153, 0),
+ gcn::Color(0, 204, 204),
+ gcn::Color(51, 0, 153),
+ gcn::Color(153, 0, 153)
+};
+/** Number of Elemets of RAINBOW_COLORS */
+const int Palette::RAINBOW_COLOR_COUNT = 7;
+
+std::string Palette::getConfigName(const std::string &typeName)
+{
+ std::string res = "Color" + typeName;
+
+ int pos = 5;
+ for (size_t i = 0; i < typeName.length(); i++)
+ {
+ if (i == 0 || typeName[i] == '_')
+ {
+ if (i > 0)
+ i++;
+
+ res[pos] = typeName[i];
+ }
+ else
+ {
+ res[pos] = tolower(typeName[i]);
+ }
+ pos++;
+ }
+ res.erase(pos, res.length() - pos);
+
+ return res;
+}
+
+DEFENUMNAMES(ColorType, COLOR_TYPE)
+
+const int Palette::GRADIENT_DELAY = 40;
+
+Palette::Palette() :
+ mRainbowTime(tick_time),
+ mColVector(ColVector(TYPE_COUNT))
+{
+ std::string indent = " ";
+ addColor(TEXT, 0x000000, STATIC, _("Text"));
+ addColor(SHADOW, 0x000000, STATIC, indent + _("Text Shadow"));
+ addColor(OUTLINE, 0x000000, STATIC, indent + _("Text Outline"));
+ addColor(PROGRESS_BAR, 0xffffff, STATIC, indent + _("Progress Bar Labels"));
+
+ addColor(BACKGROUND, 0xffffff, STATIC, _("Background"));
+
+ addColor(HIGHLIGHT, 0xebc873, STATIC, _("Highlight"), 'H');
+ addColor(TAB_HIGHLIGHT, 0xff0000, PULSE, indent + _("Tab Highlight"));
+ addColor(SHOP_WARNING, 0x910000, STATIC, indent +
+ _("Item too expensive"));
+
+ addColor(CHAT, 0x000000, STATIC, _("Chat"), 'C');
+ addColor(GM, 0xff0000, STATIC, indent + _("GM"), 'G');
+ addColor(PLAYER, 0x1fa052, STATIC, indent + _("Player"), 'Y');
+ addColor(WHISPER, 0x0000ff, STATIC, indent + _("Whisper"), 'W');
+ addColor(IS, 0xa08527, STATIC, indent + _("Is"), 'I');
+ addColor(PARTY, 0xff00d8, STATIC, indent + _("Party"), 'P');
+ addColor(SERVER, 0x8415e2, STATIC, indent + _("Server"), 'S');
+ addColor(LOGGER, 0x919191, STATIC, indent + _("Logger"), 'L');
+ addColor(HYPERLINK, 0xe50d0d, STATIC, indent + _("Hyperlink"), '<');
+
+ addColor(BEING, 0xffffff, STATIC, _("Being"));
+ addColor(PC, 0xffffff, STATIC, indent + _("Other Player's Names"));
+ addColor(SELF, 0xff8040, STATIC, indent + _("Own Name"));
+ addColor(GM_NAME, 0x00ff00, STATIC, indent + _("GM Names"));
+ addColor(NPC, 0xc8c8ff, STATIC, indent + _("NPCs"));
+ addColor(MONSTER, 0xff4040, STATIC, indent + _("Monsters"));
+
+ addColor(UNKNOWN_ITEM, 0x000000, STATIC, _("Unknown Item Type"));
+ addColor(GENERIC, 0x21a5b1, STATIC, indent + _("Generic"));
+ addColor(HEAD, 0x527fa4, STATIC, indent + _("Hat"));
+ addColor(USABLE, 0x268d24, STATIC, indent + _("Usable"));
+ addColor(TORSO, 0xd12aa4, STATIC, indent + _("Shirt"));
+ addColor(ONEHAND, 0xf42a2a, STATIC, indent + _("1 Handed Weapons"));
+ addColor(LEGS, 0x699900, STATIC, indent + _("Pants"));
+ addColor(FEET, 0xaa1d48, STATIC, indent + _("Shoes"));
+ addColor(TWOHAND, 0xf46d0e, STATIC, indent + _("2 Handed Weapons"));
+ addColor(SHIELD, 0x9c2424, STATIC, indent + _("Shield"));
+ addColor(RING, 0x0000ff, STATIC, indent + _("Ring"));
+ addColor(ARMS, 0x9c24e8, STATIC, indent + _("Arms"));
+ addColor(AMMO, 0x8b6311, STATIC, indent + _("Ammo"));
+
+ addColor(PARTICLE, 0xffffff, STATIC, _("Particle Effects"));
+ addColor(PICKUP_INFO, 0x28dc28, STATIC, indent + _("Pickup Notification"));
+ addColor(EXP_INFO, 0xffff00, STATIC, indent + _("Exp Notification"));
+ addColor(HIT_PLAYER_MONSTER, 0x0064ff, STATIC,
+ indent + _("Player hits Monster"));
+ addColor(HIT_MONSTER_PLAYER, 0xff3232, STATIC,
+ indent + _("Monster hits Player"));
+ addColor(HIT_CRITICAL, 0xff0000, RAINBOW, indent + _("Critical Hit"));
+ addColor(MISS, 0xffff00, STATIC, indent + _("Misses"));
+ commit(true);
+}
+
+Palette::~Palette()
+{
+ const std::string *configName;
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end(); col != colEnd; ++col)
+ {
+ configName = &ColorTypeNames[col->type];
+ config.setValue(*configName + "Gradient", col->committedGrad);
+ if (col->grad == STATIC || col->grad == PULSE)
+ {
+ config.setValue(*configName, toString(col->getRGB()));
+ }
+ }
+}
+
+const gcn::Color& Palette::getColor(char c, bool &valid)
+ {
+ for (ColVector::const_iterator col = mColVector.begin(),
+ colEnd = mColVector.end(); col != colEnd; ++col)
+ {
+ if (col->ch == c)
+ {
+ valid = true;
+ return col->color;
+ }
+ }
+ valid = false;
+ return BLACK;
+}
+
+void Palette::setColor(ColorType type, int r, int g, int b)
+{
+ mColVector[type].color.r = r;
+ mColVector[type].color.g = g;
+ mColVector[type].color.b = b;
+}
+
+void Palette::setGradient(ColorType type, GradientType grad)
+{
+ ColorElem *elem = &mColVector[type];
+ if (elem->grad != STATIC && grad == STATIC)
+ {
+ for (size_t i = 0; i < mGradVector.size(); i++)
+ {
+ if (mGradVector[i] == elem)
+ {
+ mGradVector.erase(mGradVector.begin() + i);
+ break;
+ }
+ }
+ }
+ else if (elem->grad == STATIC && grad != STATIC)
+ {
+ mGradVector.push_back(elem);
+ }
+
+ if (elem->grad != grad)
+ {
+ elem->grad = grad;
+ }
+}
+
+std::string Palette::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mColVector[i].text;
+}
+
+Palette::ColorType Palette::getColorTypeAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return CHAT;
+ }
+ return mColVector[i].type;
+}
+
+void Palette::commit(bool commitNonStatic)
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd; ++i)
+ {
+ i->committedGrad = i->grad;
+ if (commitNonStatic || i->grad == STATIC)
+ {
+ i->committedColor = i->color;
+ }
+ else if (i->grad == PULSE)
+ {
+ i->committedColor = i->testColor;
+ }
+ }
+}
+
+void Palette::rollback()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ if (i->grad != i->committedGrad)
+ {
+ setGradient(i->type, i->committedGrad);
+ }
+ setColor(i->type, i->committedColor.r, i->committedColor.g,
+ i->committedColor.b);
+ if (i->grad == PULSE)
+ {
+ i->testColor.r = i->committedColor.r;
+ i->testColor.g = i->committedColor.g;
+ i->testColor.b = i->committedColor.b;
+ }
+ }
+}
+
+void Palette::addColor(Palette::ColorType type, int rgb,
+ Palette::GradientType grad,
+ const std::string &text, char c)
+{
+ const std::string *configName = &ColorTypeNames[type];
+ gcn::Color trueCol = (int)config.getValue(*configName, rgb);
+ grad = (GradientType)config.getValue(*configName + "Gradient", grad);
+ mColVector[type].set(type, trueCol, grad, text, c);
+ if (grad != STATIC)
+ {
+ mGradVector.push_back(&mColVector[type]);
+ }
+}
+
+void Palette::advanceGradient ()
+{
+ if (get_elapsed_time(mRainbowTime) > 5)
+ {
+ int pos, colIndex, colVal;
+ // For slower systems, advance can be greater than one (advance > 1
+ // skips advance-1 steps). Should make gradient look the same
+ // independent of the framerate.
+ int advance = get_elapsed_time(mRainbowTime) / 5;
+ double startColVal, destColVal;
+
+ for (size_t i = 0; i < mGradVector.size(); i++)
+ {
+ mGradVector[i]->gradientIndex =
+ (mGradVector[i]->gradientIndex + advance) %
+ (GRADIENT_DELAY * ((mGradVector[i]->grad == SPECTRUM) ?
+ (mGradVector[i]->grad == PULSE) ? 255 : 6 :
+ RAINBOW_COLOR_COUNT));
+
+ pos = mGradVector[i]->gradientIndex % GRADIENT_DELAY;
+ colIndex = mGradVector[i]->gradientIndex / GRADIENT_DELAY;
+
+ if (mGradVector[i]->grad == PULSE)
+ {
+ colVal = (int) (255.0 * (sin(M_PI *
+ (mGradVector[i]->gradientIndex) / 255) + 1) / 2);
+
+ const gcn::Color* col = &mGradVector[i]->testColor;
+
+ mGradVector[i]->color.r = ((colVal * col->r) / 255) % (col->r + 1);
+ mGradVector[i]->color.g = ((colVal * col->g) / 255) % (col->g + 1);
+ mGradVector[i]->color.b = ((colVal * col->b) / 255) % (col->b + 1);
+ }
+ if (mGradVector[i]->grad == SPECTRUM)
+ {
+ if (colIndex % 2)
+ { // falling curve
+ colVal = (int)(255.0 * (cos(M_PI * pos / GRADIENT_DELAY) +
+ 1) / 2);
+ }
+ else
+ { // ascending curve
+ colVal = (int)(255.0 * (cos(M_PI * (GRADIENT_DELAY-pos) /
+ GRADIENT_DELAY) + 1) / 2);
+ }
+
+ mGradVector[i]->color.r =
+ (colIndex == 0 || colIndex == 5) ? 255 :
+ (colIndex == 1 || colIndex == 4) ? colVal : 0;
+ mGradVector[i]->color.g =
+ (colIndex == 1 || colIndex == 2) ? 255 :
+ (colIndex == 0 || colIndex == 3) ? colVal : 0;
+ mGradVector[i]->color.b =
+ (colIndex == 3 || colIndex == 4) ? 255 :
+ (colIndex == 2 || colIndex == 5) ? colVal : 0;
+ }
+ else if (mGradVector[i]->grad == RAINBOW)
+ {
+ const gcn::Color* startCol = &RAINBOW_COLORS[colIndex];
+ const gcn::Color* destCol =
+ &RAINBOW_COLORS[(colIndex + 1) % RAINBOW_COLOR_COUNT];
+
+ startColVal = (cos(M_PI * pos / GRADIENT_DELAY) + 1) / 2;
+ destColVal = 1 - startColVal;
+
+ mGradVector[i]->color.r =(int)(startColVal * startCol->r +
+ destColVal * destCol->r);
+
+ mGradVector[i]->color.g =(int)(startColVal * startCol->g +
+ destColVal * destCol->g);
+
+ mGradVector[i]->color.b =(int)(startColVal * startCol->b +
+ destColVal * destCol->b);
+ }
+ }
+
+ mRainbowTime = tick_time;
+ }
+}
diff --git a/src/gui/palette.h b/src/gui/palette.h
new file mode 100644
index 00000000..1a466ed4
--- /dev/null
+++ b/src/gui/palette.h
@@ -0,0 +1,350 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ * Copyright (C) 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALETTE_H
+#define PALETTE_H
+
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+#include <guichan/color.hpp>
+
+// Generate strings from an enum ... some preprocessor fun.
+#define EDEF(a) a,
+#define ECONFIGSTR(a) Palette::getConfigName(#a),
+
+#define TEXTENUM(name,def)\
+ enum name { def(EDEF) };\
+ static const std::string name ## Names[];
+#define DEFENUMNAMES(name,def)\
+ const std::string Palette::name ## Names[] = { def(ECONFIGSTR) "" };
+
+/**
+ * Class controlling the game's color palette.
+ */
+class Palette : public gcn::ListModel
+{
+ public:
+ /** List of all colors that are configurable. */
+ #define COLOR_TYPE(ENTRY)\
+ ENTRY(TEXT)\
+ ENTRY(SHADOW)\
+ ENTRY(OUTLINE)\
+ ENTRY(PROGRESS_BAR)\
+ ENTRY(BACKGROUND)\
+ ENTRY(HIGHLIGHT)\
+ ENTRY(TAB_HIGHLIGHT)\
+ ENTRY(SHOP_WARNING)\
+ ENTRY(CHAT)\
+ ENTRY(GM)\
+ ENTRY(PLAYER)\
+ ENTRY(WHISPER)\
+ ENTRY(IS)\
+ ENTRY(PARTY)\
+ ENTRY(SERVER)\
+ ENTRY(LOGGER)\
+ ENTRY(HYPERLINK)\
+ ENTRY(BEING)\
+ ENTRY(PC)\
+ ENTRY(SELF)\
+ ENTRY(GM_NAME)\
+ ENTRY(NPC)\
+ ENTRY(MONSTER)\
+ ENTRY(UNKNOWN_ITEM)\
+ ENTRY(GENERIC)\
+ ENTRY(HEAD)\
+ ENTRY(USABLE)\
+ ENTRY(TORSO)\
+ ENTRY(ONEHAND)\
+ ENTRY(LEGS)\
+ ENTRY(FEET)\
+ ENTRY(TWOHAND)\
+ ENTRY(SHIELD)\
+ ENTRY(RING)\
+ ENTRY(ARMS)\
+ ENTRY(AMMO)\
+ ENTRY(PARTICLE)\
+ ENTRY(EXP_INFO)\
+ ENTRY(PICKUP_INFO)\
+ ENTRY(HIT_PLAYER_MONSTER)\
+ ENTRY(HIT_MONSTER_PLAYER)\
+ ENTRY(HIT_CRITICAL)\
+ ENTRY(MISS)\
+ ENTRY(TYPE_COUNT)\
+
+ TEXTENUM(ColorType, COLOR_TYPE)
+
+ /** Colors can be static or can alter over time. */
+ enum GradientType {
+ STATIC,
+ PULSE,
+ SPECTRUM,
+ RAINBOW
+ };
+
+ /**
+ * Constructor
+ */
+ Palette();
+
+ /**
+ * Destructor
+ */
+ ~Palette();
+
+ /**
+ * Returns the color associated with a character, if it exists. Returns
+ * Palette::BLACK if the character is not found.
+ *
+ * @param c character requested
+ * @param valid indicate whether character is known
+ *
+ * @return the requested color or Palette::BLACK
+ */
+ const gcn::Color& getColor(char c, bool &valid);
+
+ /**
+ * Gets the color associated with the type. Sets the alpha channel
+ * before returning.
+ *
+ * @param type the color type requested
+ * @param alpha alpha channel to use
+ *
+ * @return the requested color
+ */
+ inline const gcn::Color& getColor(ColorType type, int alpha = 255)
+ {
+ gcn::Color* col = &mColVector[type].color;
+ col->a = alpha;
+ return *col;
+ }
+
+ /**
+ * Gets the committed color associated with the specified type.
+ *
+ * @param type the color type requested
+ *
+ * @return the requested committed color
+ */
+ inline const gcn::Color& getCommittedColor(ColorType type)
+ {
+ return mColVector[type].committedColor;
+ }
+
+ /**
+ * Gets the test color associated with the specified type.
+ *
+ * @param type the color type requested
+ *
+ * @return the requested test color
+ */
+ inline const gcn::Color& getTestColor(ColorType type)
+ {
+ return mColVector[type].testColor;
+ }
+
+ /**
+ * Sets the test color associated with the specified type.
+ *
+ * @param type the color type requested
+ * @param color the color that should be tested
+ */
+ inline void setTestColor(ColorType type, gcn::Color color)
+ {
+ mColVector[type].testColor = color;
+ }
+
+ /**
+ * Gets the GradientType associated with the specified type.
+ *
+ * @param type the color type of the color
+ *
+ * @return the gradient type of the color with the given index
+ */
+ inline GradientType getGradientType(ColorType type)
+ {
+ return mColVector[type].grad;
+ }
+
+ /**
+ * Get the character used by the specified color.
+ *
+ * @param type the color type of the color
+ *
+ * @return the color char of the color with the given index
+ */
+ inline char getColorChar(ColorType type)
+ {
+ return mColVector[type].ch;
+ }
+
+ /**
+ * Sets the color for the specified type.
+ *
+ * @param type color to be set
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ */
+ void setColor(ColorType type, int r, int g, int b);
+
+ /**
+ * Sets the gradient type for the specified color.
+ *
+ * @param grad gradient type to set
+ */
+ void setGradient(ColorType type, GradientType grad);
+
+ /**
+ * Returns the number of colors known.
+ *
+ * @return the number of colors known
+ */
+ inline int getNumberOfElements() { return mColVector.size(); }
+
+ /**
+ * Returns the name of the ith color.
+ *
+ * @param i index of color interested in
+ *
+ * @return the name of the color
+ */
+ std::string getElementAt(int i);
+
+ /**
+ * Gets the ColorType used by the color for the element at index i in
+ * the current color model.
+ *
+ * @param i the index of the color
+ *
+ * @return the color type of the color with the given index
+ */
+ ColorType getColorTypeAt(int i);
+
+ /**
+ * Commit the colors
+ */
+ inline void commit()
+ {
+ commit(false);
+ }
+
+ /**
+ * Rollback the colors
+ */
+ void rollback();
+
+ /**
+ * Updates all colors, that are non-static.
+ */
+ void advanceGradient();
+
+ private:
+ /** Black Color Constant */
+ static const gcn::Color BLACK;
+
+ /** Colors used for the rainbow gradient */
+ static const gcn::Color RAINBOW_COLORS[];
+ static const int RAINBOW_COLOR_COUNT;
+ /** Parameter to control the speed of the gradient */
+ static const int GRADIENT_DELAY;
+ /** Time tick, that gradient-type colors were updated the last time. */
+ int mRainbowTime;
+
+ /**
+ * Define a color replacement.
+ *
+ * @param i the index of the color to replace
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ */
+ void setColorAt(int i, int r, int g, int b);
+
+ /**
+ * Commit the colors. Commit the non-static color values, if
+ * commitNonStatic is true. Only needed in the constructor.
+ */
+ void commit(bool commitNonStatic);
+
+ struct ColorElem
+ {
+ ColorType type;
+ gcn::Color color;
+ gcn::Color testColor;
+ gcn::Color committedColor;
+ std::string text;
+ char ch;
+ GradientType grad;
+ GradientType committedGrad;
+ int gradientIndex;
+
+ void set(ColorType type, gcn::Color& color, GradientType grad,
+ const std::string &text, char c)
+ {
+ ColorElem::type = type;
+ ColorElem::color = color;
+ ColorElem::text = text;
+ ColorElem::ch = c;
+ ColorElem::grad = grad;
+ ColorElem::gradientIndex = rand();
+ }
+
+ inline int getRGB()
+ {
+ return (committedColor.r << 16) | (committedColor.g << 8) |
+ committedColor.b;
+ }
+ };
+ typedef std::vector<ColorElem> ColVector;
+ /** Vector containing the colors. */
+ ColVector mColVector;
+ std::vector<ColorElem*> mGradVector;
+
+ /**
+ * Initialise color
+ *
+ * @param c character that needs initialising
+ * @param rgb default color if not found in config
+ * @param text identifier of color
+ */
+ void addColor(ColorType type, int rgb, GradientType grad,
+ const std::string &text, char c = 0);
+
+ /**
+ * Prefixes the given string with "Color", lowercases all letters but
+ * the first and all following a '_'. All '_'s will be removed.
+ *
+ * E.g.: HIT_PLAYER_MONSTER -> HitPlayerMonster
+ *
+ * @param typeName string to transform
+ *
+ * @return the transformed string
+ */
+ static std::string getConfigName(const std::string& typeName);
+};
+
+extern Palette *guiPalette;
+
+#endif
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index 2bfa798c..b7e553dc 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -78,6 +78,9 @@ PlayerBox::~PlayerBox()
void PlayerBox::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
if (mPlayer)
{
// Draw character
diff --git a/src/gui/popup.cpp b/src/gui/popup.cpp
new file mode 100644
index 00000000..17d299a5
--- /dev/null
+++ b/src/gui/popup.cpp
@@ -0,0 +1,209 @@
+/*
+ * Aethyra
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra based on original code
+ * from The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <cassert>
+#include <climits>
+
+#include <guichan/exception.hpp>
+
+#include "gui.h"
+#include "skin.h"
+#include "popup.h"
+#include "window.h"
+#include "windowcontainer.h"
+
+#include "../configlistener.h"
+#include "../configuration.h"
+#include "../log.h"
+
+#include "../resources/image.h"
+
+ConfigListener *Popup::popupConfigListener = 0;
+int Popup::instances = 0;
+bool Popup::mAlphaChanged = false;
+
+class PopupConfigListener : public ConfigListener
+{
+ void optionChanged(const std::string &)
+ {
+ Popup::mAlphaChanged = true;
+ }
+};
+
+Popup::Popup(const std::string& name, Window *parent,
+ const std::string& skin):
+ mParent(parent),
+ mPopupName(name),
+ mMinWidth(100),
+ mMinHeight(40),
+ mMaxWidth(INT_MAX),
+ mMaxHeight(INT_MAX)
+{
+ logger->log("Popup::Popup(\"%s\")", name.c_str());
+
+ if (!windowContainer)
+ throw GCN_EXCEPTION("Popup::Popup(): no windowContainer set");
+
+ if (instances == 0)
+ {
+ popupConfigListener = new PopupConfigListener();
+ // Send GUI alpha changed for initialization
+ popupConfigListener->optionChanged("guialpha");
+ config.addListener("guialpha", popupConfigListener);
+ }
+
+ setPadding(3);
+
+ instances++;
+
+ // Loads the skin
+ mSkin = skinLoader->load(skin);
+
+ setGuiAlpha();
+
+ // Add this window to the window container
+ windowContainer->add(this);
+
+ // Popups are invisible by default
+ setVisible(false);
+}
+
+Popup::~Popup()
+{
+ logger->log("Popup::~Popup(\"%s\")", mPopupName.c_str());
+
+ while (!mWidgets.empty())
+ {
+ gcn::Widget *w = mWidgets.front();
+ remove(w);
+ delete(w);
+ }
+
+ instances--;
+
+ mSkin->instances--;
+
+ if (instances == 0)
+ {
+ config.removeListener("guialpha", popupConfigListener);
+ delete popupConfigListener;
+ popupConfigListener = NULL;
+ }
+}
+
+void Popup::setWindowContainer(WindowContainer *wc)
+{
+ windowContainer = wc;
+}
+
+void Popup::draw(gcn::Graphics *graphics)
+{
+ if (!isVisible())
+ return;
+
+ Graphics *g = static_cast<Graphics*>(graphics);
+
+ g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
+
+ // Update Popup alpha values
+ if (mAlphaChanged)
+ {
+ for_each(mSkin->getBorder().grid, mSkin->getBorder().grid + 9,
+ std::bind2nd(std::mem_fun(&Image::setAlpha),
+ config.getValue("guialpha", 0.8)));
+ }
+ drawChildren(graphics);
+}
+
+gcn::Rectangle Popup::getChildrenArea()
+{
+ return gcn::Rectangle(getPadding(), 0, getWidth() - getPadding() * 2,
+ getHeight() - getPadding() * 2);
+}
+
+void Popup::setContentSize(int width, int height)
+{
+ width += 2 * getPadding();
+ height += 2 * getPadding();
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
+}
+
+void Popup::setLocationRelativeTo(gcn::Widget *widget)
+{
+ int wx, wy;
+ int x, y;
+
+ widget->getAbsolutePosition(wx, wy);
+ getAbsolutePosition(x, y);
+
+ setPosition(getX() + (wx + (widget->getWidth() - getWidth()) / 2 - x),
+ getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y));
+}
+
+void Popup::setMinWidth(unsigned int width)
+{
+ mMinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
+}
+
+void Popup::setMinHeight(unsigned int height)
+{
+ mMinHeight = height > mSkin->getMinHeight() ? height : mSkin->getMinHeight();
+}
+
+void Popup::setMaxWidth(unsigned int width)
+{
+ mMaxWidth = width;
+}
+
+void Popup::setMaxHeight(unsigned int height)
+{
+ mMaxHeight = height;
+}
+
+void Popup::scheduleDelete()
+{
+ windowContainer->scheduleDelete(this);
+}
+
+void Popup::setGuiAlpha()
+{
+ //logger->log("Popup::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8));
+ for (int i = 0; i < 9; i++)
+ {
+ //logger->log("Popup::setGuiAlpha: Border Image (%i)", i);
+ mSkin->getBorder().grid[i]->setAlpha(config.getValue("guialpha", 0.8));
+ }
+
+ mAlphaChanged = false;
+}
+
diff --git a/src/gui/popup.h b/src/gui/popup.h
new file mode 100644
index 00000000..bfe8d7e9
--- /dev/null
+++ b/src/gui/popup.h
@@ -0,0 +1,194 @@
+/*
+ * Aethyra
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra based on original code
+ * from The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef POPUP_H
+#define POPUP_H
+
+#include <guichan/widgets/container.hpp>
+
+#include "../graphics.h"
+#include "../guichanfwd.h"
+
+class ConfigListener;
+class Skin;
+class SkinLoader;
+class Window;
+class WindowContainer;
+
+/**
+ * A rather reduced down version of the Window class that is particularly suited
+ * for
+ *
+ * \ingroup GUI
+ */
+class Popup : public gcn::Container
+{
+ public:
+ friend class PopupConfigListener;
+
+ /**
+ * Constructor. Initializes the title to the given text and hooks
+ * itself into the popup container.
+ *
+ * @param name A human readable name for the popup. Only useful for
+ * debugging purposes.
+ * @param parent The parent Window. This is the Window standing above
+ * this one in the Window hiearchy. When reordering,
+ * a Popup will never go below its parent Window.
+ * @param skin The location where the Popup's skin XML can be found.
+ */
+ Popup(const std::string& name = "", Window *parent = NULL,
+ const std::string &skin = "graphics/gui/gui.xml");
+
+ /**
+ * Destructor. Deletes all the added widgets.
+ */
+ ~Popup();
+
+ /**
+ * Sets the window container to be used by new popups.
+ */
+ static void setWindowContainer(WindowContainer *windowContainer);
+
+ /**
+ * Draws the popup.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Sets the size of this popup.
+ */
+ void setContentSize(int width, int height);
+
+ /**
+ * Sets the location relative to the given widget.
+ */
+ void setLocationRelativeTo(gcn::Widget *widget);
+
+ /**
+ * Sets the minimum width of the popup.
+ */
+ void setMinWidth(unsigned int width);
+
+ /**
+ * Sets the minimum height of the popup.
+ */
+ void setMinHeight(unsigned int height);
+
+ /**
+ * Sets the maximum width of the popup.
+ */
+ void setMaxWidth(unsigned int width);
+
+ /**
+ * Sets the minimum height of the popup.
+ */
+ void setMaxHeight(unsigned int height);
+
+ /**
+ * Gets the minimum width of the popup.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ /**
+ * Gets the minimum height of the popup.
+ */
+ int getMinHeight() { return mMinHeight; }
+
+ /**
+ * Gets the maximum width of the popup.
+ */
+ int getMaxWidth() { return mMaxWidth; }
+
+ /**
+ * Gets the minimum height of the popup.
+ */
+ int getMaxHeight() { return mMaxHeight; }
+
+ /**
+ * Gets the padding of the popup. The padding is the distance between
+ * the popup border and the content.
+ *
+ * @return The padding of the popup.
+ * @see setPadding
+ */
+ unsigned int getPadding() const { return mPadding; }
+
+ /**
+ * Sets the padding of the popup. The padding is the distance between the
+ * popup border and the content.
+ *
+ * @param padding The padding of the popup.
+ * @see getPadding
+ */
+ void setPadding(unsigned int padding) { mPadding = padding; }
+
+ /**
+ * Returns the parent Window.
+ *
+ * @return The parent Window or <code>NULL</code> if there is none.
+ */
+ Window* getParentWindow() { return mParent; }
+
+ /**
+ * Sets the name of the popup. This is only useful for debug purposes.
+ */
+ void setPopupName(const std::string &name) { mPopupName = name; }
+
+ /**
+ * Returns the name of the popup. This is only useful for debug purposes.
+ */
+ const std::string& getPopupName() { return mPopupName; }
+
+ /**
+ * Schedule this popup for deletion. It will be deleted at the start
+ * of the next logic update.
+ */
+ void scheduleDelete();
+
+ // Inherited from BasicContainer
+
+ virtual gcn::Rectangle getChildrenArea();
+
+ private:
+ void setGuiAlpha();
+
+ Window *mParent; /**< The parent Window (if there is one) */
+ std::string mPopupName; /**< Name of the Popup */
+ static bool mAlphaChanged; /**< Whether the alpha percent was changed */
+ int mMinWidth; /**< Minimum Popup width */
+ int mMinHeight; /**< Minimum Popup height */
+ int mMaxWidth; /**< Maximum Popup width */
+ int mMaxHeight; /**< Maximum Popup height */
+ unsigned int mPadding; /**< Holds the padding of the window. */
+
+ /**
+ * The config listener that listens to changes relevant to all Popups.
+ */
+ static ConfigListener *popupConfigListener;
+
+ static int instances; /**< Number of Popup instances */
+
+ Skin* mSkin; /**< Skin in use by this Popup */
+};
+
+#endif
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index ced44f42..9ff9b23f 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -26,11 +26,11 @@
#include "inventorywindow.h"
#include "item_amount.h"
#include "popupmenu.h"
-#include "windowcontainer.h"
#include "../being.h"
#include "../beingmanager.h"
#include "../floor_item.h"
+#include "../graphics.h"
#include "../item.h"
#include "../localplayer.h"
#include "../npc.h"
@@ -75,7 +75,7 @@ void PopupMenu::showPopup(int x, int y, Being *being)
{
case Being::PLAYER:
{
- // Players can be traded with. Later also attack, follow and
+ // Players can be traded with. Later also follow and
// add as buddy will be options in this menu.
const std::string &name = being->getName();
mBrowserBox->addRow(strprintf(_("@@trade|Trade With %s@@"), name.c_str()));
@@ -345,10 +345,10 @@ void PopupMenu::showPopup(int x, int y, Item *item)
void PopupMenu::showPopup(int x, int y)
{
setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8);
- if (windowContainer->getWidth() < (x + getWidth() + 5))
- x = windowContainer->getWidth() - getWidth();
- if (windowContainer->getHeight() < (y + getHeight() + 5))
- y = windowContainer->getHeight() - getHeight();
+ if (graphics->getWidth() < (x + getWidth() + 5))
+ x = graphics->getWidth() - getWidth();
+ if (graphics->getHeight() < (y + getHeight() + 5))
+ y = graphics->getHeight() - getHeight();
setPosition(x, y);
setVisible(true);
requestMoveToTop();
diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h
index 2694abd8..0a6877d9 100644
--- a/src/gui/popupmenu.h
+++ b/src/gui/popupmenu.h
@@ -22,8 +22,6 @@
#ifndef POPUP_MENU_H
#define POPUP_MENU_H
-#include <SDL.h> // for Uint32
-
#include "linkhandler.h"
#include "window.h"
@@ -68,7 +66,7 @@ class PopupMenu : public Window, public LinkHandler
private:
BrowserBox* mBrowserBox;
- Uint32 mBeingId;
+ int mBeingId;
FloorItem* mFloorItem;
Item *mItem;
diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp
index 85f21604..02ddab16 100644
--- a/src/gui/progressbar.cpp
+++ b/src/gui/progressbar.cpp
@@ -22,7 +22,9 @@
#include <guichan/font.hpp>
#include "gui.h"
+#include "palette.h"
#include "progressbar.h"
+#include "textrenderer.h"
#include "../configuration.h"
#include "../graphics.h"
@@ -139,32 +141,22 @@ void ProgressBar::draw(gcn::Graphics *graphics)
// The bar
if (mProgress > 0)
{
-
graphics->setColor(gcn::Color(mRed, mGreen, mBlue, alpha));
graphics->fillRectangle(gcn::Rectangle(4, 4,
- (int) (mProgress * (getWidth() - 8)),
- getHeight() - 8));
+ (int) (mProgress * (getWidth() - 8)),
+ getHeight() - 8));
}
// The label
if (!mText.empty())
{
- gcn::Font *f = boldFont;
const int textX = getWidth() / 2;
- const int textY = (getHeight() - f->getHeight()) / 2;
-
- graphics->setFont(f);
-
- graphics->setColor(gcn::Color(0, 0, 0, alpha));
- graphics->drawText(mText, textX + 1, textY, gcn::Graphics::CENTER);
- graphics->drawText(mText, textX, textY - 1, gcn::Graphics::CENTER);
- graphics->drawText(mText, textX, textY + 1, gcn::Graphics::CENTER);
- graphics->drawText(mText, textX - 1, textY, gcn::Graphics::CENTER);
-
- graphics->setColor(gcn::Color(255, 255, 255, alpha));
- graphics->drawText(mText, textX, textY, gcn::Graphics::CENTER);
+ const int textY = (getHeight() - boldFont->getHeight()) / 2;
- graphics->setColor(gcn::Color(0, 0, 0));
+ TextRenderer::renderText(graphics, mText, textX, textY,
+ gcn::Graphics::CENTER,
+ guiPalette->getColor(Palette::PROGRESS_BAR,
+ alpha), boldFont, true, false);
}
}
diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h
index 49bc3edd..e75b1d44 100644
--- a/src/gui/progressbar.h
+++ b/src/gui/progressbar.h
@@ -124,10 +124,13 @@ class ProgressBar : public gcn::Widget
bool mSmoothColorChange;
std::string mText;
+ bool mUpdated;
static ImageRect mBorder;
static int mInstances;
static float mAlpha;
+
+ static const gcn::Color TEXT_COLOR;
};
#endif
diff --git a/src/gui/radiobutton.cpp b/src/gui/radiobutton.cpp
index c8ae2fad..52ceb837 100644
--- a/src/gui/radiobutton.cpp
+++ b/src/gui/radiobutton.cpp
@@ -69,6 +69,9 @@ RadioButton::~RadioButton()
void RadioButton::drawBox(gcn::Graphics* graphics)
{
+ if (!isVisible())
+ return;
+
if (config.getValue("guialpha", 0.8) != mAlpha)
{
mAlpha = config.getValue("guialpha", 0.8);
diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp
index a94af4cc..0536188c 100644
--- a/src/gui/recorder.cpp
+++ b/src/gui/recorder.cpp
@@ -40,9 +40,11 @@ Recorder::Recorder(ChatWindow *chat, const std::string &title,
mChat = chat;
Button *button = new Button(buttonTxt, "activate", this);
- setDefaultSize(0, windowContainer->getHeight() - 123 - button->getHeight() -
- offsetY, button->getWidth() + offsetX, button->getHeight() +
- offsetY);
+
+ // 123 is the default chat window height. If you change this in Chat, please
+ // change it here as well
+ setDefaultSize(button->getWidth() + offsetX, button->getHeight() +
+ offsetY, ImageRect::LOWER_LEFT, 0, 123);
place(0, 0, button);
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 216ac211..5fb8b579 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "../configuration.h"
#include "../log.h"
#include "../logindata.h"
@@ -28,6 +26,7 @@
#include "button.h"
#include "checkbox.h"
+#include "label.h"
#include "login.h"
#include "ok_dialog.h"
#include "passwordfield.h"
@@ -49,23 +48,20 @@ void WrongDataNoticeListener::setTarget(gcn::TextField *textField)
void WrongDataNoticeListener::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok")
- {
mTarget->requestFocus();
- }
}
-
RegisterDialog::RegisterDialog(LoginData *loginData):
Window(_("Register")),
mWrongDataNoticeListener(new WrongDataNoticeListener),
mLoginData(loginData)
{
- gcn::Label *userLabel = new gcn::Label(_("Name:"));
- gcn::Label *passwordLabel = new gcn::Label(_("Password:"));
- gcn::Label *confirmLabel = new gcn::Label(_("Confirm:"));
+ gcn::Label *userLabel = new Label(_("Name:"));
+ gcn::Label *passwordLabel = new Label(_("Password:"));
+ gcn::Label *confirmLabel = new Label(_("Confirm:"));
#ifdef EATHENA_SUPPORT
- gcn::Label *serverLabel = new gcn::Label(_("Server:"));
- gcn::Label *portLabel = new gcn::Label(_("Port:"));
+ gcn::Label *serverLabel = new Label(_("Server:"));
+ gcn::Label *portLabel = new Label(_("Port:"));
#endif
mUserField = new TextField(loginData->username);
mPasswordField = new PasswordField(loginData->password);
@@ -131,7 +127,7 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
mPortField->addActionListener(this);
#endif
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
mUserField->requestFocus();
mUserField->setCaretPosition(mUserField->getText().length());
diff --git a/src/gui/register.h b/src/gui/register.h
index fde82a40..c37305e4 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -37,7 +37,8 @@ class OkDialog;
* to the field which contained wrong data when the Ok button was pressed on
* the error notice.
*/
-class WrongDataNoticeListener : public gcn::ActionListener {
+class WrongDataNoticeListener : public gcn::ActionListener
+{
public:
void setTarget(gcn::TextField *textField);
void action(const gcn::ActionEvent &event);
diff --git a/src/gui/scrollarea.cpp b/src/gui/scrollarea.cpp
index 70504a03..44ef929b 100644
--- a/src/gui/scrollarea.cpp
+++ b/src/gui/scrollarea.cpp
@@ -145,6 +145,9 @@ void ScrollArea::init()
void ScrollArea::logic()
{
+ if (!isVisible())
+ return;
+
gcn::ScrollArea::logic();
gcn::Widget *content = getContent();
@@ -167,6 +170,9 @@ void ScrollArea::logic()
void ScrollArea::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
if (mVBarVisible)
{
drawUpButton(graphics);
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index cab88560..22f56195 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
+#include "label.h"
#include "scrollarea.h"
#include "sell.h"
#include "shop.h"
@@ -55,29 +54,36 @@ SellDialog::SellDialog(Network *network):
{
setWindowName("Sell");
setResizable(true);
+ setCloseButton(true);
setMinWidth(260);
setMinHeight(230);
- setDefaultSize(0, 0, 260, 230);
+ setDefaultSize(260, 230, ImageRect::CENTER);
- mShopItems = new ShopItems;
+ // Create a ShopItems instance, that is aware of duplicate entries.
+ mShopItems = new ShopItems(true);
mShopItemList = new ShopListBox(mShopItems, mShopItems);
mScrollArea = new ScrollArea(mShopItemList);
+ mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+
mSlider = new Slider(1.0);
- mQuantityLabel = new gcn::Label("0");
- mMoneyLabel = new gcn::Label(strprintf(_("Price: %s / Total: %s"),
- "", ""));
+
+ mQuantityLabel = new Label(strprintf("%d / %d", mAmountItems, mMaxItems));
+ mQuantityLabel->setAlignment(gcn::Graphics::CENTER);
+ mMoneyLabel = new Label(strprintf(_("Price: %s / Total: %s"),
+ "", ""));
+
mIncreaseButton = new Button("+", "+", this);
mDecreaseButton = new Button("-", "-", this);
mSellButton = new Button(_("Sell"), "sell", this);
mQuitButton = new Button(_("Quit"), "quit", this);
- mItemDescLabel = new gcn::Label(strprintf(_("Description: %s"), ""));
- mItemEffectLabel = new gcn::Label(strprintf(_("Effect: %s"), ""));
+ mAddMaxButton = new Button(_("Max"), "max", this);
+ mItemDescLabel = new Label(strprintf(_("Description: %s"), ""));
+ mItemEffectLabel = new Label(strprintf(_("Effect: %s"), ""));
- mIncreaseButton->setSize(20, 20);
- mDecreaseButton->setSize(20, 20);
+ mDecreaseButton->adjustSize();
+ mDecreaseButton->setWidth(mIncreaseButton->getWidth());
- mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mIncreaseButton->setEnabled(false);
mDecreaseButton->setEnabled(false);
mSellButton->setEnabled(false);
@@ -88,21 +94,26 @@ SellDialog::SellDialog(Network *network):
mSlider->setActionEventId("slider");
mSlider->addActionListener(this);
- place(0, 0, mScrollArea, 5).setPadding(3);
- place(0, 1, mQuantityLabel, 2);
- place(2, 1, mSlider, 3);
- place(0, 2, mMoneyLabel, 5);
- place(0, 3, mItemEffectLabel, 5);
- place(0, 4, mItemDescLabel, 5);
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+
+ place(0, 0, mScrollArea, 8, 5).setPadding(3);
place(0, 5, mDecreaseButton);
- place(1, 5, mIncreaseButton);
- place(3, 5, mSellButton);
- place(4, 5, mQuitButton);
+ place(1, 5, mSlider, 3);
+ place(4, 5, mIncreaseButton);
+ place(5, 5, mQuantityLabel, 2);
+ place(7, 5, mAddMaxButton);
+ place(0, 6, mMoneyLabel, 8);
+ place(0, 7, mItemEffectLabel, 8);
+ place(0, 8, mItemDescLabel, 8);
+ place(6, 9, mSellButton);
+ place(7, 9, mQuitButton);
+
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
+ center();
loadWindowState();
- setLocationRelativeTo(getParent());
}
SellDialog::~SellDialog()
@@ -136,9 +147,8 @@ void SellDialog::addItem(const Item *item, int price)
if (!item)
return;
- mShopItems->addItem(
- item->getInvIndex(), item->getId(),
- item->getQuantity(), price);
+ mShopItems->addItem(item->getInvIndex(), item->getId(),
+ item->getQuantity(), price);
mShopItemList->adjustSize();
}
@@ -147,15 +157,14 @@ void SellDialog::addItem(const Item *item, int price)
void SellDialog::action(const gcn::ActionEvent &event)
{
- int selectedItem = mShopItemList->getSelected();
-
if (event.getId() == "quit")
{
- setVisible(false);
- if (current_npc) current_npc->handleDeath();
+ close();
return;
}
+ int selectedItem = mShopItemList->getSelected();
+
// The following actions require a valid item selection
if (selectedItem == -1 ||
selectedItem >= (int) mShopItems->getNumberOfElements())
@@ -180,6 +189,12 @@ void SellDialog::action(const gcn::ActionEvent &event)
mSlider->setValue(mAmountItems);
updateButtonsAndLabels();
}
+ else if (event.getId() == "max")
+ {
+ mAmountItems = mMaxItems;
+ mSlider->setValue(mAmountItems);
+ updateButtonsAndLabels();
+ }
else if (event.getId() == "sell" && mAmountItems > 0
&& mAmountItems <= mMaxItems)
{
@@ -189,24 +204,35 @@ void SellDialog::action(const gcn::ActionEvent &event)
#else
// Attempt sell
MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_SELL_REQUEST);
- outMsg.writeInt16(8);
- outMsg.writeInt16(mShopItems->at(selectedItem)->getInvIndex());
- outMsg.writeInt16(mAmountItems);
-#endif
+ ShopItem* item = mShopItems->at(selectedItem);
+ int sellCount;
+ mPlayerMoney +=
+ mAmountItems * mShopItems->at(selectedItem)->getPrice();
mMaxItems -= mAmountItems;
- mShopItems->getShop()->at(selectedItem)->setQuantity(mMaxItems);
+ while (mAmountItems > 0) {
+ outMsg.writeInt16(CMSG_NPC_SELL_REQUEST);
+ outMsg.writeInt16(8);
+ outMsg.writeInt16(item->getCurrentInvIndex());
+ // This order is important, item->getCurrentInvIndex() would return
+ // the inventory index of the next Duplicate otherwise.
+ sellCount = item->sellCurrentDuplicate(mAmountItems);
+ mAmountItems -= sellCount;
+ outMsg.writeInt16(sellCount);
+ }
+#endif
+
mPlayerMoney +=
mAmountItems * mShopItems->at(selectedItem)->getPrice();
mAmountItems = 1;
+ mSlider->setValue(0);
if (!mMaxItems)
{
// All were sold
mShopItemList->setSelected(-1);
- mShopItems->getShop()->erase(
- mShopItems->getShop()->begin() + selectedItem);
+ delete mShopItems->at(selectedItem);
+ mShopItems->erase(selectedItem);
gcn::Rectangle scroll;
scroll.y = mShopItemList->getRowHeight() * (selectedItem + 1);
@@ -278,5 +304,26 @@ void SellDialog::updateButtonsAndLabels()
mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems));
mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"),
Units::formatCurrency(income).c_str(),
- Units::formatCurrency(mPlayerMoney - income).c_str()));
+ Units::formatCurrency(mPlayerMoney + income).c_str()));
+}
+
+void SellDialog::logic()
+{
+ Window::logic();
+
+ if (!current_npc) setVisible(false);
+}
+
+void SellDialog::setVisible(bool visible)
+{
+ Window::setVisible(visible);
+
+ if (visible)
+ requestFocus();
+}
+
+void SellDialog::close()
+{
+ setVisible(false);
+ current_npc = 0;
}
diff --git a/src/gui/sell.h b/src/gui/sell.h
index f64a6fd5..b6388a1f 100644
--- a/src/gui/sell.h
+++ b/src/gui/sell.h
@@ -91,6 +91,20 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
*/
void setMoney(int amount);
+ /**
+ * Check for current NPC
+ */
+ void logic();
+
+ /**
+ * Sets the visibility of this window.
+ */
+ void setVisible(bool visible);
+
+ /**
+ * Closes the Buy Window, as well as resetting the current npc.
+ */
+ void close();
private:
/**
* Updates the state of buttons and labels.
@@ -102,6 +116,7 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
#endif
gcn::Button *mSellButton;
gcn::Button *mQuitButton;
+ gcn::Button *mAddMaxButton;
gcn::Button *mIncreaseButton;
gcn::Button *mDecreaseButton;
ShopListBox *mShopItemList;
@@ -119,4 +134,6 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener
int mAmountItems;
};
+extern SellDialog *sellDialog;
+
#endif
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index c8b7f900..72dfbce5 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -34,19 +34,27 @@
#include "../utils/gettext.h"
extern Window *chatWindow;
-extern Window *equipmentWindow;
-extern Window *helpWindow;
+extern Window *statusWindow;
+extern Window *buyDialog;
+extern Window *sellDialog;
+extern Window *buySellDialog;
extern Window *inventoryWindow;
-extern Window *minimap;
+extern Window *emoteWindow;
+extern Window *npcTextDialog;
+extern Window *npcStringDialog;
extern Window *skillDialog;
-extern Window *statusWindow;
+extern Window *minimap;
+extern Window *equipmentWindow;
+extern Window *tradeWindow;
+extern Window *helpWindow;
+extern Window *debugWindow;
extern Window *itemShortcutWindow;
extern Window *emoteShortcutWindow;
-extern Window *emoteWindow;
-extern Window *tradeWindow;
#ifdef TMWSERV_SUPPORT
extern Window *magicDialog;
extern Window *guildWindow;
+#else
+extern Window *storageWindow;
#endif
Setup::Setup():
@@ -68,9 +76,9 @@ Setup::Setup():
btn->setPosition(x, height - btn->getHeight() - 5);
add(btn);
- // Disable this button when the windows aren't created yet
+ // Store this button, as it needs to be enabled/disabled
if (!strcmp(*curBtn, "Reset Windows"))
- btn->setEnabled(statusWindow != NULL);
+ mResetWindows = btn;
}
TabbedArea *panel = new TabbedArea;
@@ -104,7 +112,9 @@ Setup::Setup():
add(panel);
- setLocationRelativeTo(getParent());
+ center();
+
+ setInGame(false);
}
Setup::~Setup()
@@ -131,20 +141,37 @@ void Setup::action(const gcn::ActionEvent &event)
if (!statusWindow)
return;
- statusWindow->resetToDefaultSize();
- minimap->resetToDefaultSize();
chatWindow->resetToDefaultSize();
+ statusWindow->resetToDefaultSize();
+ buyDialog->resetToDefaultSize();
+ sellDialog->resetToDefaultSize();
+#ifdef EATHENA_SUPPORT
+ buySellDialog->resetToDefaultSize();
+#endif
inventoryWindow->resetToDefaultSize();
+ emoteWindow->resetToDefaultSize();
+ npcTextDialog->resetToDefaultSize();
+ npcStringDialog->resetToDefaultSize();
+ skillDialog->resetToDefaultSize();
+ minimap->resetToDefaultSize();
equipmentWindow->resetToDefaultSize();
+ tradeWindow->resetToDefaultSize();
helpWindow->resetToDefaultSize();
- skillDialog->resetToDefaultSize();
+ debugWindow->resetToDefaultSize();
itemShortcutWindow->resetToDefaultSize();
emoteShortcutWindow->resetToDefaultSize();
- emoteWindow->resetToDefaultSize();
- tradeWindow->resetToDefaultSize();
#ifdef TMWSERV_SUPPORT
magicDialog->resetToDefaultSize();
guildWindow->resetToDefaultSize();
+#else
+ storageWindow->resetToDefaultSize();
#endif
}
}
+
+void Setup::setInGame(bool inGame)
+{
+ mResetWindows->setEnabled(inGame);
+}
+
+Setup* setupWindow;
diff --git a/src/gui/setup.h b/src/gui/setup.h
index e4eb0902..4c387d34 100644
--- a/src/gui/setup.h
+++ b/src/gui/setup.h
@@ -55,8 +55,16 @@ class Setup : public Window, public gcn::ActionListener
*/
void action(const gcn::ActionEvent &event);
+ /**
+ * Enables the reset button when in game.
+ */
+ void setInGame(bool inGame);
+
private:
std::list<SetupTab*> mTabs;
+ gcn::Button *mResetWindows;
};
+extern Setup* setupWindow;
+
#endif
diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp
index 43cc28e6..28a80b3d 100644
--- a/src/gui/setup_audio.cpp
+++ b/src/gui/setup_audio.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "checkbox.h"
+#include "label.h"
#include "ok_dialog.h"
#include "setup_audio.h"
#include "slider.h"
@@ -45,8 +44,8 @@ Setup_Audio::Setup_Audio():
setOpaque(false);
setDimension(gcn::Rectangle(0, 0, 250, 200));
- gcn::Label *sfxLabel = new gcn::Label(_("Sfx volume"));
- gcn::Label *musicLabel = new gcn::Label(_("Music volume"));
+ gcn::Label *sfxLabel = new Label(_("Sfx volume"));
+ gcn::Label *musicLabel = new Label(_("Music volume"));
mSfxSlider->setActionEventId("sfx");
mMusicSlider->setActionEventId("music");
@@ -80,7 +79,8 @@ void Setup_Audio::apply()
if (mSoundCheckBox->isSelected())
{
config.setValue("sound", 1);
- try {
+ try
+ {
sound.init();
}
catch (const char *err)
diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp
index 49c99996..033ba372 100644
--- a/src/gui/setup_colors.cpp
+++ b/src/gui/setup_colors.cpp
@@ -23,13 +23,14 @@
#include <cmath>
#include <guichan/listmodel.hpp>
-#include <guichan/widgets/label.hpp>
#include <guichan/widgets/slider.hpp>
#include "browserbox.h"
-#include "color.h"
+#include "gui.h"
#include "itemlinkhandler.h"
+#include "label.h"
#include "listbox.h"
+#include "palette.h"
#include "scrollarea.h"
#include "setup_colors.h"
#include "slider.h"
@@ -42,71 +43,91 @@
#include "../utils/gettext.h"
#include "../utils/stringutils.h"
+const std::string Setup_Colors::rawmsg = _("This is what the color looks like");
+
Setup_Colors::Setup_Colors() :
mSelected(-1)
{
setOpaque(false);
- mColorBox = new ListBox(textColor);
+ mColorBox = new ListBox(guiPalette);
mColorBox->setActionEventId("color_box");
mColorBox->addActionListener(this);
mScroll = new ScrollArea(mColorBox);
mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextPreview = new TextPreview(&rawmsg);
+
mPreview = new BrowserBox(BrowserBox::AUTO_WRAP);
mPreview->setOpaque(false);
- // Replace this later with a more appropriate link handler. For now, this'll
- // do, as it'll do nothing when clicked on.
- mPreview->setLinkHandler(new ItemLinkHandler);
+ // don't do anything with links
+ mPreview->setLinkHandler(NULL);
mPreviewBox = new ScrollArea(mPreview);
mPreviewBox->setHeight(20);
mPreviewBox->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER,
gcn::ScrollArea::SHOW_NEVER);
- mRedLabel = new gcn::Label(_("Red: "));
+ mGradTypeLabel = new Label(_("Type: "));
+
+ mGradTypeSlider = new Slider(0, 3);
+ mGradTypeSlider->setWidth(160);
+ mGradTypeSlider->setActionEventId("slider_grad");
+ mGradTypeSlider->setValue(0);
+ mGradTypeSlider->addActionListener(this);
+ mGradTypeSlider->setEnabled(false);
+
+ mGradTypeText = new Label();
+
+ mRedLabel = new Label(_("Red: "));
mRedText = new TextField;
mRedText->setWidth(40);
mRedText->setRange(0, 255);
mRedText->setNumeric(true);
mRedText->addListener(this);
+ mRedText->setEnabled(false);
mRedSlider = new Slider(0, 255);
mRedSlider->setWidth(160);
mRedSlider->setValue(mRedText->getValue());
mRedSlider->setActionEventId("slider_red");
mRedSlider->addActionListener(this);
+ mRedSlider->setEnabled(false);
- mGreenLabel = new gcn::Label(_("Green: "));
+ mGreenLabel = new Label(_("Green: "));
mGreenText = new TextField;
mGreenText->setWidth(40);
mGreenText->setRange(0, 255);
mGreenText->setNumeric(true);
mGreenText->addListener(this);
+ mGreenText->setEnabled(false);
mGreenSlider = new Slider(0, 255);
mGreenSlider->setWidth(160);
mGreenSlider->setValue(mGreenText->getValue());
mGreenSlider->setActionEventId("slider_green");
mGreenSlider->addActionListener(this);
+ mGreenSlider->setEnabled(false);
- mBlueLabel = new gcn::Label(_("Blue: "));
+ mBlueLabel = new Label(_("Blue: "));
mBlueText = new TextField;
mBlueText->setWidth(40);
mBlueText->setRange(0, 255);
mBlueText->setNumeric(true);
mBlueText->addListener(this);
+ mBlueText->setEnabled(false);
mBlueSlider = new Slider(0, 255);
mBlueSlider->setWidth(160);
mBlueSlider->setValue(mBlueText->getValue());
mBlueSlider->setActionEventId("slider_blue");
mBlueSlider->addActionListener(this);
+ mBlueSlider->setEnabled(false);
setOpaque(false);
@@ -114,8 +135,11 @@ Setup_Colors::Setup_Colors() :
LayoutHelper h(this);
ContainerPlacer place = h.getPlacer(0, 0);
- place(0, 0, mScroll, 4, 7).setPadding(2);
- place(0, 7, mPreviewBox, 4).setPadding(2);
+ place(0, 0, mScroll, 4, 6).setPadding(2);
+ place(0, 6, mPreviewBox, 4).setPadding(2);
+ place(0, 7, mGradTypeLabel, 2);
+ place(2, 7, mGradTypeSlider);
+ place(3, 7, mGradTypeText);
place(0, 8, mRedLabel, 2);
place(2, 8, mRedSlider);
place(3, 8, mRedText).setPadding(1);
@@ -131,19 +155,10 @@ Setup_Colors::Setup_Colors() :
Setup_Colors::~Setup_Colors()
{
- delete mRedLabel;
- delete mRedSlider;
- delete mRedText;
-
- delete mGreenLabel;
- delete mGreenSlider;
- delete mGreenText;
-
- delete mBlueLabel;
- delete mBlueSlider;
- delete mBlueText;
-
- delete mScroll;
+ if (mPreviewBox->getContent() == mPreview)
+ delete mTextPreview;
+ else
+ delete mPreview;
}
void Setup_Colors::action(const gcn::ActionEvent &event)
@@ -151,22 +166,140 @@ void Setup_Colors::action(const gcn::ActionEvent &event)
if (event.getId() == "color_box")
{
mSelected = mColorBox->getSelected();
- int col = textColor->getColorAt(mSelected);
- char ch = textColor->getColorCharAt(mSelected);
- std::string msg;
+ Palette::ColorType type = guiPalette->getColorTypeAt(mSelected);
+ const gcn::Color *col = &guiPalette->getColor(type);
+ Palette::GradientType grad = guiPalette->getGradientType(type);
- if (ch == '<')
- msg = toString("@@|") +
- _("This is what the color looks like") + "@@";
- else
- msg = "##" + toString(ch) +
- _("This is what the color looks like");
+ std::string msg;
+ char ch = guiPalette->getColorChar(type);
mPreview->clearRows();
- mPreview->addRow(msg);
- setEntry(mRedSlider, mRedText, col >> 16);
- setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
- setEntry(mBlueSlider, mBlueText, col & 0xff);
+ mPreviewBox->setContent(mTextPreview);
+ mTextPreview->setFont(gui->getFont());
+ mTextPreview->setTextColor(&guiPalette->getColor(Palette::TEXT));
+ mTextPreview->setTextBGColor(NULL);
+ mTextPreview->setOpaque(false);
+ mTextPreview->setShadow(true);
+ mTextPreview->setOutline(true);
+ mTextPreview->useTextAlpha(false);
+
+ switch (type)
+ {
+ case Palette::TEXT:
+ case Palette::SHADOW:
+ case Palette::OUTLINE:
+ mTextPreview->setFont(gui->getFont());
+ mTextPreview->setShadow(type == Palette::SHADOW);
+ mTextPreview->setOutline(type == Palette::OUTLINE);
+ break;
+ case Palette::PROGRESS_BAR:
+ mTextPreview->useTextAlpha(true);
+ mTextPreview->setFont(boldFont);
+ mTextPreview->setTextColor(col);
+ mTextPreview->setOutline(true);
+ mTextPreview->setShadow(false);
+ break;
+ case Palette::TAB_HIGHLIGHT:
+ mTextPreview->setFont(gui->getFont());
+ mTextPreview->setTextColor(col);
+ mTextPreview->setOutline(false);
+ mTextPreview->setShadow(false);
+ break;
+ case Palette::BACKGROUND:
+ case Palette::SHOP_WARNING:
+ mTextPreview->setBGColor(col);
+ mTextPreview->setOpaque(true);
+ mTextPreview->setOutline(false);
+ mTextPreview->setShadow(false);
+ break;
+ case Palette::HIGHLIGHT:
+ mTextPreview->setTextBGColor(col);
+ mTextPreview->setOutline(false);
+ mTextPreview->setShadow(false);
+ mPreview->addRow(rawmsg);
+ break;
+ case Palette::CHAT:
+ case Palette::GM:
+ case Palette::PLAYER:
+ case Palette::WHISPER:
+ case Palette::IS:
+ case Palette::PARTY:
+ case Palette::SERVER:
+ case Palette::LOGGER:
+ case Palette::HYPERLINK:
+ mPreviewBox->setContent(mPreview);
+ mPreview->clearRows();
+
+ if (ch == '<')
+ msg = toString("@@|") + rawmsg + "@@";
+ else
+ msg = "##" + toString(ch) + rawmsg;
+
+ mPreview->addRow(msg);
+ break;
+ case Palette::UNKNOWN_ITEM:
+ case Palette::GENERIC:
+ case Palette::HEAD:
+ case Palette::USABLE:
+ case Palette::TORSO:
+ case Palette::ONEHAND:
+ case Palette::LEGS:
+ case Palette::FEET:
+ case Palette::TWOHAND:
+ case Palette::SHIELD:
+ case Palette::RING:
+ case Palette::ARMS:
+ case Palette::AMMO:
+ mTextPreview->setFont(boldFont);
+ mTextPreview->setTextColor(col);
+ mTextPreview->setOutline(false);
+ mTextPreview->setShadow(false);
+ break;
+ case Palette::PARTICLE:
+ case Palette::EXP_INFO:
+ case Palette::PICKUP_INFO:
+ case Palette::HIT_PLAYER_MONSTER:
+ case Palette::HIT_MONSTER_PLAYER:
+ case Palette::HIT_CRITICAL:
+ case Palette::MISS:
+ mTextPreview->setShadow(false);
+ case Palette::BEING:
+ case Palette::PC:
+ case Palette::SELF:
+ case Palette::GM_NAME:
+ case Palette::NPC:
+ case Palette::MONSTER:
+ mTextPreview->setFont(boldFont);
+ mTextPreview->setTextColor(col);
+ case Palette::TYPE_COUNT:
+ break;
+ }
+
+ if (grad != Palette::STATIC && grad != Palette::PULSE)
+ { // If nonstatic color, don't display the current, but the committed
+ // color at the sliders
+ col = &guiPalette->getCommittedColor(type);
+ }
+ else if (grad == Palette::PULSE)
+ {
+ col = &guiPalette->getTestColor(type);
+ }
+
+ setEntry(mRedSlider, mRedText, col->r);
+ setEntry(mGreenSlider, mGreenText, col->g);
+ setEntry(mBlueSlider, mBlueText, col->b);
+
+ mGradTypeSlider->setValue(grad);
+ updateGradType();
+ mGradTypeSlider->setEnabled(true);
+
+ return;
+ }
+
+ if (event.getId() == "slider_grad")
+ {
+ updateGradType();
+ updateColor();
return;
}
@@ -202,16 +335,18 @@ void Setup_Colors::setEntry(gcn::Slider *s, TextField *t, int value)
void Setup_Colors::apply()
{
- textColor->commit();
+ guiPalette->commit();
}
void Setup_Colors::cancel()
{
- textColor->rollback();
- int col = textColor->getColorAt(mSelected);
- setEntry(mRedSlider, mRedText, col >> 16);
- setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
- setEntry(mBlueSlider, mBlueText, col & 0xff);
+ guiPalette->rollback();
+ Palette::ColorType type = guiPalette->getColorTypeAt(mSelected);
+ const gcn::Color *col = &guiPalette->getColor(type);
+ mGradTypeSlider->setValue(guiPalette->getGradientType(type));
+ setEntry(mRedSlider, mRedText, col->r);
+ setEntry(mGreenSlider, mGreenText, col->g);
+ setEntry(mBlueSlider, mBlueText, col->b);
}
void Setup_Colors::listen(const TextField *tf)
@@ -236,14 +371,51 @@ void Setup_Colors::listen(const TextField *tf)
}
}
+void Setup_Colors::updateGradType()
+{
+ if (mSelected == -1)
+ return;
+
+ mSelected = mColorBox->getSelected();
+ Palette::ColorType type = guiPalette->getColorTypeAt(mSelected);
+ Palette::GradientType grad = guiPalette->getGradientType(type);
+
+ mGradTypeText->setCaption(
+ (grad == Palette::STATIC) ? _("Static") :
+ (grad == Palette::PULSE) ? _("Pulse") :
+ (grad == Palette::RAINBOW) ? _("Rainbow") : _("Spectrum"));
+
+ bool enable = (grad == Palette::STATIC || grad == Palette::PULSE);
+ mRedText->setEnabled(enable);
+ mRedSlider->setEnabled(enable);
+ mGreenText->setEnabled(enable);
+ mGreenSlider->setEnabled(enable);
+ mBlueText->setEnabled(enable);
+ mBlueSlider->setEnabled(enable);
+}
+
void Setup_Colors::updateColor()
{
if (mSelected == -1)
- {
return;
+
+ Palette::ColorType type = guiPalette->getColorTypeAt(mSelected);
+ Palette::GradientType grad =
+ static_cast<Palette::GradientType>(mGradTypeSlider->getValue());
+ guiPalette->setGradient(type, grad);
+
+ if (grad == Palette::STATIC)
+ {
+ guiPalette->setColor(type,
+ static_cast<int>(mRedSlider->getValue()),
+ static_cast<int>(mGreenSlider->getValue()),
+ static_cast<int>(mBlueSlider->getValue()));
+ }
+ else if (grad == Palette::PULSE)
+ {
+ guiPalette->setTestColor(type, gcn::Color(
+ static_cast<int>(mRedSlider->getValue()),
+ static_cast<int>(mGreenSlider->getValue()),
+ static_cast<int>(mBlueSlider->getValue())));
}
- int rgb = static_cast<int>(mRedSlider->getValue()) << 16 |
- static_cast<int>(mGreenSlider->getValue()) << 8 |
- static_cast<int>(mBlueSlider->getValue());
- textColor->setColorAt(mSelected, rgb);
}
diff --git a/src/gui/setup_colors.h b/src/gui/setup_colors.h
index 2831297f..52d3f727 100644
--- a/src/gui/setup_colors.h
+++ b/src/gui/setup_colors.h
@@ -34,6 +34,8 @@
#include "../guichanfwd.h"
+#include "widgets/textpreview.h"
+
class BrowserBox;
class Setup_Colors : public SetupTab, public gcn::ActionListener,
@@ -48,12 +50,19 @@ class Setup_Colors : public SetupTab, public gcn::ActionListener,
void listen(const TextField *tf);
private:
+ static const std::string rawmsg;
+
gcn::ListBox *mColorBox;
gcn::ScrollArea *mScroll;
BrowserBox *mPreview;
+ TextPreview *mTextPreview;
gcn::ScrollArea *mPreviewBox;
int mSelected;
+ gcn::Label *mGradTypeLabel;
+ gcn::Slider *mGradTypeSlider;
+ gcn::Label *mGradTypeText;
+
gcn::Label *mRedLabel;
gcn::Slider *mRedSlider;
TextField *mRedText;
@@ -71,5 +80,6 @@ class Setup_Colors : public SetupTab, public gcn::ActionListener,
void setEntry(gcn::Slider *s, TextField *t, int value);
void updateColor();
+ void updateGradType();
};
#endif
diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp
index c0c04949..59a882c7 100644
--- a/src/gui/setup_joystick.cpp
+++ b/src/gui/setup_joystick.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "checkbox.h"
+#include "label.h"
#include "setup_joystick.h"
#include "widgets/layouthelper.h"
@@ -35,7 +34,7 @@
extern Joystick *joystick;
Setup_Joystick::Setup_Joystick():
- mCalibrateLabel(new gcn::Label(_("Press the button to start calibration"))),
+ mCalibrateLabel(new Label(_("Press the button to start calibration"))),
mCalibrateButton(new Button(_("Calibrate"), "calibrate", this)),
mJoystickEnabled(new CheckBox(_("Enable joystick")))
{
diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp
index 96792436..1451e71e 100644
--- a/src/gui/setup_players.cpp
+++ b/src/gui/setup_players.cpp
@@ -22,10 +22,9 @@
#include <string>
#include <vector>
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
#include "checkbox.h"
+#include "label.h"
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
@@ -137,7 +136,7 @@ public:
for (unsigned int r = 0; r < player_names->size(); ++r)
{
std::string name = (*player_names)[r];
- gcn::Widget *widget = new gcn::Label(name);
+ gcn::Widget *widget = new Label(name);
mWidgets.push_back(widget);
gcn::ListModel *playerRelation = new PlayerRelationListModel;
@@ -247,7 +246,7 @@ Setup_Players::Setup_Players():
for (int i = 0; i < COLUMNS_NR; i++)
{
mPlayerTableTitleModel->set(0, i,
- new gcn::Label(gettext(table_titles[i])));
+ new Label(gettext(table_titles[i])));
}
mPlayerTitleTable->setLinewiseSelection(true);
@@ -257,7 +256,7 @@ Setup_Players::Setup_Players():
mPlayerTable->setLinewiseSelection(true);
mPlayerTable->addActionListener(this);
- gcn::Label *ignore_action_label = new gcn::Label(_("When ignoring:"));
+ gcn::Label *ignore_action_label = new Label(_("When ignoring:"));
mIgnoreActionChoicesBox->setActionEventId(ACTION_STRATEGY);
mIgnoreActionChoicesBox->addActionListener(this);
@@ -329,7 +328,7 @@ void Setup_Players::apply()
~(PlayerRelation::TRADE |
PlayerRelation::WHISPER);
player_relations.setDefault(old_default_relations
- | (mDefaultTrading->isSelected() ?
+ | (mDefaultTrading->isSelected() ?
PlayerRelation::TRADE : 0)
| (mDefaultWhisper->isSelected() ?
PlayerRelation::WHISPER : 0));
@@ -341,7 +340,7 @@ void Setup_Players::cancel()
void Setup_Players::action(const gcn::ActionEvent &event)
{
- if (event.getId() == ACTION_TABLE)
+ if (event.getId() == ACTION_TABLE)
{
// temporarily eliminate ourselves: we are fully aware of this change,
// so there is no need for asynchronous updates. (In fact, thouse
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 526c67ce..07f073db 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -26,9 +26,8 @@
#include <guichan/key.hpp>
#include <guichan/listmodel.hpp>
-#include <guichan/widgets/label.hpp>
-
#include "checkbox.h"
+#include "label.h"
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
@@ -88,13 +87,15 @@ ModeListModel::ModeListModel()
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
/* Check which modes are available */
- if (modes == (SDL_Rect **)0) {
+ if (modes == (SDL_Rect **)0)
logger->log("No modes available");
- } else if (modes == (SDL_Rect **)-1) {
+ else if (modes == (SDL_Rect **)-1)
logger->log("All resolutions available");
- } else {
+ else
+ {
//logger->log("Available Modes");
- for (int i = 0; modes[i]; ++i) {
+ for (int i = 0; modes[i]; ++i)
+ {
const std::string modeString =
toString((int)modes[i]->w) + "x" + toString((int)modes[i]->h);
//logger->log(modeString.c_str());
@@ -110,6 +111,8 @@ Setup_Video::Setup_Video():
mVisibleNamesEnabled(config.getValue("visiblenames", 1)),
mParticleEffectsEnabled(config.getValue("particleeffects", true)),
mNameEnabled(config.getValue("showownname", false)),
+ mPickupChatEnabled(config.getValue("showpickupchat", true)),
+ mPickupParticleEnabled(config.getValue("showpickupparticle", false)),
mOpacity(config.getValue("guialpha", 0.8)),
mFps((int) config.getValue("fpslimit", 0)),
mSpeechMode((int) config.getValue("speech", 3)),
@@ -121,11 +124,15 @@ Setup_Video::Setup_Video():
mVisibleNamesCheckBox(new CheckBox(_("Visible names"), mVisibleNamesEnabled)),
mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)),
mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)),
+ mPickupNotifyLabel(new Label(_("Show pickup notification"))),
+ mPickupChatCheckBox(new CheckBox(_("in chat"), mPickupChatEnabled)),
+ mPickupParticleCheckBox(new CheckBox(_("as particle"),
+ mPickupParticleEnabled)),
mSpeechSlider(new Slider(0, 3)),
- mSpeechLabel(new gcn::Label("")),
+ mSpeechLabel(new Label("")),
mAlphaSlider(new Slider(0.2, 1.0)),
mFpsCheckBox(new CheckBox(_("FPS Limit:"))),
- mFpsSlider(new Slider(10, 200)),
+ mFpsSlider(new Slider(10, 120)),
mFpsField(new TextField),
mOriginalScrollLaziness((int) config.getValue("ScrollLaziness", 16)),
mScrollLazinessSlider(new Slider(1, 64)),
@@ -135,22 +142,22 @@ Setup_Video::Setup_Video():
mScrollRadiusField(new TextField),
mOverlayDetail((int) config.getValue("OverlayDetail", 2)),
mOverlayDetailSlider(new Slider(0, 2)),
- mOverlayDetailField(new gcn::Label("")),
+ mOverlayDetailField(new Label("")),
mParticleDetail(3 - (int) config.getValue("particleEmitterSkip", 1)),
mParticleDetailSlider(new Slider(0, 3)),
- mParticleDetailField(new gcn::Label(""))
+ mParticleDetailField(new Label(""))
{
setOpaque(false);
ScrollArea *scrollArea = new ScrollArea(mModeList);
scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- speechLabel = new gcn::Label(_("Overhead text"));
- alphaLabel = new gcn::Label(_("Gui opacity"));
- scrollRadiusLabel = new gcn::Label(_("Scroll radius"));
- scrollLazinessLabel = new gcn::Label(_("Scroll laziness"));
- overlayDetailLabel = new gcn::Label(_("Ambient FX"));
- particleDetailLabel = new gcn::Label(_("Particle Detail"));
+ speechLabel = new Label(_("Overhead text"));
+ alphaLabel = new Label(_("Gui opacity"));
+ scrollRadiusLabel = new Label(_("Scroll radius"));
+ scrollLazinessLabel = new Label(_("Scroll laziness"));
+ overlayDetailLabel = new Label(_("Ambient FX"));
+ particleDetailLabel = new Label(_("Particle Detail"));
mModeList->setEnabled(true);
#ifndef USE_OPENGL
@@ -172,6 +179,8 @@ Setup_Video::Setup_Video():
mCustomCursorCheckBox->setActionEventId("customcursor");
mVisibleNamesCheckBox->setActionEventId("visiblenames");
mParticleEffectsCheckBox->setActionEventId("particleeffects");
+ mPickupChatCheckBox->setActionEventId("pickupchat");
+ mPickupParticleCheckBox->setActionEventId("pickupparticle");
mNameCheckBox->setActionEventId("showownname");
mAlphaSlider->setActionEventId("guialpha");
mFpsCheckBox->setActionEventId("fpslimitcheckbox");
@@ -190,6 +199,8 @@ Setup_Video::Setup_Video():
mCustomCursorCheckBox->addActionListener(this);
mVisibleNamesCheckBox->addActionListener(this);
mParticleEffectsCheckBox->addActionListener(this);
+ mPickupChatCheckBox->addActionListener(this);
+ mPickupParticleCheckBox->addActionListener(this);
mNameCheckBox->addActionListener(this);
mAlphaSlider->addActionListener(this);
mFpsCheckBox->addActionListener(this);
@@ -264,12 +275,15 @@ Setup_Video::Setup_Video():
ContainerPlacer place = h.getPlacer(0, 0);
place(0, 0, scrollArea, 1, 6).setPadding(2);
- place(1, 0, mFsCheckBox, 3);
- place(1, 1, mOpenGLCheckBox, 3);
- place(1, 2, mCustomCursorCheckBox, 3);
- place(1, 3, mVisibleNamesCheckBox, 3);
- place(1, 4, mNameCheckBox, 3);
- place(1, 5, mParticleEffectsCheckBox, 3);
+ place(1, 0, mFsCheckBox, 2);
+ place(3, 0, mOpenGLCheckBox, 1);
+ place(1, 1, mCustomCursorCheckBox, 3);
+ place(1, 2, mVisibleNamesCheckBox, 3);
+ place(3, 2, mNameCheckBox, 1);
+ place(1, 3, mParticleEffectsCheckBox, 3);
+ place(1, 4, mPickupNotifyLabel, 3);
+ place(1, 5, mPickupChatCheckBox, 1);
+ place(2, 5, mPickupParticleCheckBox, 2);
place(0, 6, mAlphaSlider);
place(0, 7, mFpsSlider);
@@ -279,7 +293,7 @@ Setup_Video::Setup_Video():
place(0, 11, mOverlayDetailSlider);
place(0, 12, mParticleDetailSlider);
- place(1, 6, alphaLabel, 2);
+ place(1, 6, alphaLabel, 3);
place(1, 7, mFpsCheckBox).setPadding(3);
place(1, 8, scrollRadiusLabel);
place(1, 9, scrollLazinessLabel);
@@ -290,9 +304,9 @@ Setup_Video::Setup_Video():
place(2, 7, mFpsField).setPadding(1);
place(2, 8, mScrollRadiusField).setPadding(1);
place(2, 9, mScrollLazinessField).setPadding(1);
- place(2, 10, mSpeechLabel, 2).setPadding(2);
- place(2, 11, mOverlayDetailField, 2).setPadding(2);
- place(2, 12, mParticleDetailField, 2).setPadding(2);
+ place(2, 10, mSpeechLabel, 3).setPadding(2);
+ place(2, 11, mOverlayDetailField, 3).setPadding(2);
+ place(2, 12, mParticleDetailField, 3).setPadding(2);
setDimension(gcn::Rectangle(0, 0, 325, 280));
}
@@ -329,9 +343,11 @@ void Setup_Video::apply()
}
}
#if defined(WIN32) || defined(__APPLE__)
- } else {
+ }
+ else
+ {
new OkDialog(_("Switching to full screen"),
- _("Restart needed for changes to take effect."));
+ _("Restart needed for changes to take effect."));
}
#endif
config.setValue("screen", fullscreen ? true : false);
@@ -344,7 +360,7 @@ void Setup_Video::apply()
// OpenGL can currently only be changed by restarting, notify user.
new OkDialog(_("Changing OpenGL"),
- _("Applying change to OpenGL requires restart."));
+ _("Applying change to OpenGL requires restart."));
}
// FPS change
@@ -360,6 +376,8 @@ void Setup_Video::apply()
mOpacity = config.getValue("guialpha", 0.8);
mOverlayDetail = (int) config.getValue("OverlayDetail", 2);
mOpenGLEnabled = config.getValue("opengl", false);
+ mPickupChatEnabled = config.getValue("showpickupchat", true);
+ mPickupParticleEnabled = config.getValue("showpickupparticle", false);
}
int Setup_Video::updateSlider(gcn::Slider *slider, gcn::TextField *field,
@@ -406,8 +424,13 @@ void Setup_Video::cancel()
config.setValue("particleeffects", mParticleEffectsEnabled ? true : false);
config.setValue("speech", mSpeechMode);
config.setValue("showownname", mNameEnabled ? true : false);
+ if (player_node)
+ player_node->mUpdateName = true;
config.setValue("guialpha", mOpacity);
config.setValue("opengl", mOpenGLEnabled ? true : false);
+ config.setValue("showpickupchat", mPickupChatEnabled ? true : false);
+ config.setValue("showpickupparticle", mPickupParticleEnabled ?
+ true : false);
}
void Setup_Video::action(const gcn::ActionEvent &event)
@@ -443,8 +466,19 @@ void Setup_Video::action(const gcn::ActionEvent &event)
{
config.setValue("particleeffects",
mParticleEffectsCheckBox->isSelected() ? true : false);
- new OkDialog(_("Particle effect settings changed"),
- _("Restart your client or change maps for the change to take effect."));
+ new OkDialog(_("Particle effect settings changed."),
+ _("Restart your client or change maps "
+ "for the change to take effect."));
+ }
+ else if (event.getId() == "pickupchat")
+ {
+ config.setValue("showpickupchat", mPickupChatCheckBox->isSelected()
+ ? true : false);
+ }
+ else if (event.getId() == "pickupparticle")
+ {
+ config.setValue("showpickupparticle",
+ mPickupParticleCheckBox->isSelected() ? true : false);
}
else if (event.getId() == "speech")
{
@@ -558,9 +592,9 @@ void Setup_Video::keyPressed(gcn::KeyEvent &event)
{
mFps = 10;
}
- else if (mFps > 200)
+ else if (mFps > 120)
{
- mFps = 200;
+ mFps = 120;
}
mFpsField->setText(toString(mFps));
mFpsSlider->setValue(mFps);
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index 44ecdfe5..d2680fa8 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -53,6 +53,8 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
bool mVisibleNamesEnabled;
bool mParticleEffectsEnabled;
bool mNameEnabled;
+ bool mPickupChatEnabled;
+ bool mPickupParticleEnabled;
double mOpacity;
int mFps;
int mSpeechMode;
@@ -74,6 +76,10 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
gcn::CheckBox *mParticleEffectsCheckBox;
gcn::CheckBox *mNameCheckBox;
+ gcn::Label *mPickupNotifyLabel;
+ gcn::CheckBox *mPickupChatCheckBox;
+ gcn::CheckBox *mPickupParticleCheckBox;
+
gcn::Slider *mSpeechSlider;
gcn::Label *mSpeechLabel;
gcn::Slider *mAlphaSlider;
diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp
index 7b28cef4..3cdc304c 100644
--- a/src/gui/shop.cpp
+++ b/src/gui/shop.cpp
@@ -23,6 +23,11 @@
#include "../utils/dtor.h"
+ShopItems::ShopItems(bool mergeDuplicates) :
+ mMergeDuplicates(mergeDuplicates)
+{
+}
+
ShopItems::~ShopItems()
{
clear();
@@ -40,15 +45,27 @@ std::string ShopItems::getElementAt(int i)
void ShopItems::addItem(int id, int amount, int price)
{
- mShopItems.push_back(new ShopItem(id, amount, price));
+ mShopItems.push_back(new ShopItem(-1, id, amount, price));
}
#ifdef EATHENA_SUPPORT
-void ShopItems::addItem(int inventoryIndex, int id, int amount, int price)
+void ShopItems::addItem(int inventoryIndex, int id, int quantity, int price)
{
- ShopItem *item = new ShopItem(id, amount, price);
- item->setInvIndex(inventoryIndex);
- mShopItems.push_back(item);
+ ShopItem* item = 0;
+ if (mMergeDuplicates)
+ {
+ item = findItem(id);
+ }
+
+ if (item)
+ {
+ item->addDuplicate (inventoryIndex, quantity);
+ }
+ else
+ {
+ item = new ShopItem(inventoryIndex, id, quantity, price);
+ mShopItems.push_back(item);
+ }
}
#endif
@@ -57,13 +74,30 @@ ShopItem* ShopItems::at(int i) const
return mShopItems.at(i);
}
+void ShopItems::erase(int i)
+{
+ mShopItems.erase(mShopItems.begin() + i);
+}
+
void ShopItems::clear()
{
delete_all(mShopItems);
mShopItems.clear();
}
-std::vector<ShopItem*>* ShopItems::getShop()
+ShopItem* ShopItems::findItem(int id)
{
- return &mShopItems;
+ ShopItem *item;
+
+ std::vector<ShopItem*>::iterator it;
+ for(it = mShopItems.begin(); it != mShopItems.end(); it++)
+ {
+ item = *(it);
+ if (item->getId() == id)
+ {
+ return item;
+ }
+ }
+
+ return 0;
}
diff --git a/src/gui/shop.h b/src/gui/shop.h
index aa72bf2a..6c3031af 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -31,10 +31,27 @@
class ShopItem;
+/**
+ * This class handles the list of items available in a shop.
+ *
+ * The addItem routine can automatically check, if an item already exists and
+ * only adds duplicates to the old item, if one is found. The original
+ * distribution of the duplicates can be retrieved from the item.
+ *
+ * This functionality can be enabled in the constructor.
+ */
class ShopItems : public gcn::ListModel
{
public:
/**
+ * Constructor. Creates a new ShopItems instance.
+ *
+ * @param mergeDuplicates lets the Shop look for duplicate entries and
+ * merges them to one item.
+ */
+ ShopItems(bool mergeDuplicates = false);
+
+ /**
* Destructor.
*/
~ShopItems();
@@ -46,18 +63,28 @@ class ShopItems : public gcn::ListModel
#ifdef EATHENA_SUPPORT
/**
- * Adds an item to the list (used by eAthena sell dialog).
+ * Adds an item to the list (used by sell dialog). Looks for
+ * duplicate entries, if mergeDuplicates was turned on.
+ *
+ * @param inventoryIndex the inventory index of the item
+ * @param id the id of the item
+ * @param quantity number of available copies of the item
+ * @param price price of the item
*/
void addItem(int inventoryIndex, int id, int amount, int price);
#endif
/**
* Returns the number of items in the shop.
+ *
+ * @return the number of items in the shop
*/
int getNumberOfElements();
/**
* Returns the name of item number i in the shop.
+ *
+ * @param i the index to retrieve
*/
std::string getElementAt(int i);
@@ -67,17 +94,31 @@ class ShopItems : public gcn::ListModel
ShopItem* at(int i) const;
/**
+ * Removes an element from the shop.
+ *
+ * @param i index to remove
+ */
+ void erase(int i);
+
+ /**
* Clear the vector.
*/
void clear();
+ private:
/**
- * Direct access to the vector.
+ * Searches the current items in the shop for the specified
+ * id and returns the item if found, or 0 else.
+ *
+ * @return the item found or 0
*/
- std::vector<ShopItem*>* getShop();
+ ShopItem* findItem(int id);
- private:
+ /** the shop storage */
std::vector<ShopItem*> mShopItems;
+
+ /** Look for duplicate entries on addition */
+ bool mMergeDuplicates;
};
#endif
diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp
index 8aed3c77..aa42c294 100644
--- a/src/gui/shoplistbox.cpp
+++ b/src/gui/shoplistbox.cpp
@@ -22,7 +22,7 @@
#include <guichan/font.hpp>
#include <guichan/listmodel.hpp>
-#include "color.h"
+#include "palette.h"
#include "shop.h"
#include "shoplistbox.h"
@@ -57,17 +57,15 @@ void ShopListBox::setPlayersMoney(int money)
void ShopListBox::draw(gcn::Graphics *gcnGraphics)
{
- if (!mListModel)
+ if (!mListModel || !isVisible())
return;
if (config.getValue("guialpha", 0.8) != mAlpha)
mAlpha = config.getValue("guialpha", 0.8);
- bool valid;
- const int red = (textColor->getColor('H', valid) >> 16) & 0xFF;
- const int green = (textColor->getColor('H', valid) >> 8) & 0xFF;
- const int blue = textColor->getColor('H', valid) & 0xFF;
- const int alpha = (int)(mAlpha * 255.0f);
+ int alpha = (int)(mAlpha * 255.0f);
+ const gcn::Color* highlightColor =
+ &guiPalette->getColor(Palette::HIGHLIGHT, alpha);
Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
@@ -78,19 +76,27 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
i < mListModel->getNumberOfElements();
++i, y += mRowHeight)
{
- gcn::Color backgroundColor = gcn::Color(255, 255, 255, alpha);
+ gcn::Color temp;
+ const gcn::Color* backgroundColor =
+ &guiPalette->getColor(Palette::BACKGROUND, alpha);
- if (i == mSelected)
- {
- backgroundColor = gcn::Color(red, green, blue, alpha);
- }
- else if (mShopItems &&
+ if (mShopItems &&
mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck)
- {
- backgroundColor = gcn::Color(145, 145, 145, alpha);
- }
+ if (i != mSelected)
+ backgroundColor = &guiPalette->getColor(Palette::SHOP_WARNING,
+ alpha);
+ else
+ {
+ temp = guiPalette->getColor(Palette::SHOP_WARNING, alpha);
+ temp.r = (temp.r + highlightColor->r) / 2;
+ temp.g = (temp.g + highlightColor->g) / 2;
+ temp.b = (temp.g + highlightColor->b) / 2;
+ backgroundColor = &temp;
+ }
+ else if (i == mSelected)
+ backgroundColor = highlightColor;
- graphics->setColor(backgroundColor);
+ graphics->setColor(*backgroundColor);
graphics->fillRectangle(gcn::Rectangle(0, y, getWidth(), mRowHeight));
if (mShopItems)
@@ -101,21 +107,12 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
graphics->drawImage(icon, 1, y);
}
}
- graphics->setColor(gcn::Color(0, 0, 0));
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
graphics->drawText(mListModel->getElementAt(i), ITEM_ICON_SIZE + 5,
y + (ITEM_ICON_SIZE - getFont()->getHeight()) / 2);
}
}
-void ShopListBox::mousePressed(gcn::MouseEvent &event)
-{
- if (event.getButton() == gcn::MouseEvent::LEFT)
- {
- setSelected(event.getY() / mRowHeight);
- distributeActionEvent();
- }
-}
-
void ShopListBox::adjustSize()
{
if (mListModel)
diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h
index cde4786e..5d3378b1 100644
--- a/src/gui/shoplistbox.h
+++ b/src/gui/shoplistbox.h
@@ -56,8 +56,6 @@ class ShopListBox : public ListBox
*/
unsigned int getRowHeight() const { return mRowHeight; }
- void mousePressed(gcn::MouseEvent &event);
-
/**
* gives information about the current player's money
*/
diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp
index 74609fa1..901095e5 100644
--- a/src/gui/shortcutcontainer.cpp
+++ b/src/gui/shortcutcontainer.cpp
@@ -38,34 +38,27 @@ ShortcutContainer::ShortcutContainer():
void ShortcutContainer::widgetResized(const gcn::Event &event)
{
mGridWidth = getWidth() / mBoxWidth;
+
if (mGridWidth < 1)
- {
mGridWidth = 1;
- }
- setHeight((mMaxItems / mGridWidth +
- (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight);
+ setHeight((mMaxItems / mGridWidth) * mBoxHeight);
mGridHeight = getHeight() / mBoxHeight;
+
if (mGridHeight < 1)
- {
mGridHeight = 1;
- }
}
int ShortcutContainer::getIndexFromGrid(int pointX, int pointY) const
{
- const gcn::Rectangle tRect = gcn::Rectangle(
- 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight);
- if (!tRect.isPointInRect(pointX, pointY))
- {
- return -1;
- }
- const int index = ((pointY / mBoxHeight) * mGridWidth) +
- pointX / mBoxWidth;
- if (index >= mMaxItems)
- {
- return -1;
- }
+ const gcn::Rectangle tRect = gcn::Rectangle(0, 0, mGridWidth * mBoxWidth,
+ mGridHeight * mBoxHeight);
+
+ int index = ((pointY / mBoxHeight) * mGridWidth) + pointX / mBoxWidth;
+
+ if (!tRect.isPointInRect(pointX, pointY) || index >= mMaxItems)
+ index = -1;
+
return index;
}
diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp
index c704fc44..dcc7f72e 100644
--- a/src/gui/shortcutwindow.cpp
+++ b/src/gui/shortcutwindow.cpp
@@ -23,6 +23,8 @@
#include "shortcutcontainer.h"
#include "shortcutwindow.h"
+#include "widgets/layout.h"
+
#include "../configuration.h"
static const int SCROLL_PADDING = 0;
@@ -39,29 +41,28 @@ ShortcutWindow::ShortcutWindow(const char *title, ShortcutContainer *content)
mItems = content;
- mInstances++;
-
const int border = SCROLL_PADDING * 2 + getPadding() * 2;
setMinWidth(mItems->getBoxWidth() + border);
setMinHeight(mItems->getBoxHeight() + border);
setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border);
setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border);
- const int width = (int) config.getValue("screenwidth", 800);
- const int height = (int) config.getValue("screenheight", 600);
+ setDefaultSize(mItems->getBoxWidth() + border, (mItems->getBoxHeight() *
+ mItems->getMaxItems()) + border, ImageRect::LOWER_RIGHT,
+ mInstances * mItems->getBoxWidth(), 0);
- setDefaultSize(width - (mInstances * mItems->getBoxWidth()) -
- (mInstances * border), height - (mItems->getBoxHeight() *
- mItems->getMaxItems()) - border, mItems->getBoxWidth() +
- border, (mItems->getBoxHeight() * mItems->getMaxItems()) +
- border);
+ mInstances++;
mScrollArea = new ScrollArea(mItems);
mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING);
mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mScrollArea->setOpaque(false);
- add(mScrollArea);
+ place(0, 0, mScrollArea, 5, 5).setPadding(0);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+ layout.setMargin(0);
loadWindowState();
}
@@ -71,13 +72,3 @@ ShortcutWindow::~ShortcutWindow()
delete mItems;
}
-void ShortcutWindow::widgetResized(const gcn::Event &event)
-{
- Window::widgetResized(event);
-
- const gcn::Rectangle &area = getChildrenArea();
-
- mScrollArea->setSize(
- area.width - SCROLL_PADDING,
- area.height - SCROLL_PADDING);
-}
diff --git a/src/gui/shortcutwindow.h b/src/gui/shortcutwindow.h
index 64592328..eae881ba 100644
--- a/src/gui/shortcutwindow.h
+++ b/src/gui/shortcutwindow.h
@@ -45,11 +45,6 @@ class ShortcutWindow : public Window
*/
~ShortcutWindow();
- /**
- * Called whenever the widget changes size.
- */
- void widgetResized(const gcn::Event &event);
-
private:
ShortcutWindow();
ShortcutContainer *mItems;
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index 61bb9ce9..39ccbb06 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
+#include "label.h"
#include "listbox.h"
#include "scrollarea.h"
#include "skill.h"
@@ -102,13 +101,13 @@ public:
info = &fakeSkillInfo;
sprintf(tmp, "%c%s", info->modifiable? ' ' : '*', info->name.c_str());
- gcn::Label *name_label = new gcn::Label(tmp);
+ gcn::Label *name_label = new Label(tmp);
sprintf(tmp, "Lv:%i", skill->lv);
- gcn::Label *lv_label = new gcn::Label(tmp);
+ gcn::Label *lv_label = new Label(tmp);
sprintf(tmp, "Sp:%i", skill->sp);
- gcn::Label *sp_label = new gcn::Label(tmp);
+ gcn::Label *sp_label = new Label(tmp);
set(i, 0, name_label);
set(i, 1, lv_label);
@@ -136,13 +135,13 @@ SkillDialog::SkillDialog():
setWindowName("Skills");
setCloseButton(true);
- setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260);
+ setDefaultSize(255, 260, ImageRect::CENTER);
setMinHeight(50 + mTableModel->getHeight());
setMinWidth(200);
ScrollArea *skillScrollArea = new ScrollArea(mTable);
- mPointsLabel = new gcn::Label(strprintf(_("Skill points: %d"), 0));
+ mPointsLabel = new Label(strprintf(_("Skill points: %d"), 0));
mIncButton = new Button(_("Up"), _("inc"), this);
mUseButton = new Button(_("Use"), _("use"), this);
mUseButton->setEnabled(false);
@@ -157,13 +156,13 @@ SkillDialog::SkillDialog():
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
- setLocationRelativeTo(getParent());
+ center();
loadWindowState();
}
SkillDialog::~SkillDialog()
{
- delete mTable;
+ delete_all(mSkillList);
}
void SkillDialog::action(const gcn::ActionEvent &event)
diff --git a/src/gui/skin.cpp b/src/gui/skin.cpp
new file mode 100644
index 00000000..d44c54a8
--- /dev/null
+++ b/src/gui/skin.cpp
@@ -0,0 +1,191 @@
+/*
+ * Aethyra
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "skin.h"
+
+#include "../log.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/dtor.h"
+#include "../utils/xml.h"
+
+SkinLoader* skinLoader = NULL;
+
+Skin::Skin(ImageRect skin, Image* close, std::string name):
+ instances(0),
+ mName(name),
+ border(skin),
+ closeImage(close)
+{
+}
+
+Skin::~Skin()
+{
+ // Clean up static resources
+ for (int i = 0; i < 9; i++)
+ {
+ delete border.grid[i];
+ border.grid[i] = NULL;
+ }
+
+ closeImage->decRef();
+}
+
+unsigned int Skin::getMinWidth()
+{
+ return (border.grid[0]->getWidth() + border.grid[1]->getWidth()) +
+ border.grid[2]->getWidth();
+}
+
+unsigned int Skin::getMinHeight()
+{
+ return (border.grid[0]->getHeight() + border.grid[3]->getHeight()) +
+ border.grid[6]->getHeight();
+}
+
+Skin* SkinLoader::load(const std::string &filename)
+{
+ SkinIterator skinIterator = mSkins.find(filename);
+
+ if (mSkins.end() != skinIterator)
+ {
+ skinIterator->second->instances++;
+ return skinIterator->second;
+ }
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ logger->log("Loading Skin '%s'.", filename.c_str());
+
+ if (filename.empty())
+ logger->error("SkinLoader::load(): Invalid File Name.");
+
+ // TODO:
+ // If there is an error loading the specified file, we should try to revert
+ // to a 'default' skin file. Only if the 'default' skin file can't be loaded
+ // should we have a terminating error.
+ XML::Document doc(filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
+ logger->error("Widget Skinning error");
+
+ std::string skinSetImage;
+ skinSetImage = XML::getProperty(rootNode, "image", "");
+ Image *dBorders = NULL;
+ ImageRect border;
+
+ if (!skinSetImage.empty())
+ {
+ logger->log("SkinLoader::load(): <skinset> defines "
+ "'%s' as a skin image.", skinSetImage.c_str());
+ dBorders = resman->getImage("graphics/gui/" + skinSetImage);
+ }
+ else
+ {
+ logger->error("SkinLoader::load(): Skinset does not define an image!");
+ }
+
+ //iterate <widget>'s
+ for_each_xml_child_node(widgetNode, rootNode)
+ {
+ if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
+ continue;
+
+ std::string widgetType;
+ widgetType = XML::getProperty(widgetNode, "type", "unknown");
+ if (widgetType == "Window")
+ {
+ // Iterate through <part>'s
+ // LEEOR / TODO:
+ // We need to make provisions to load in a CloseButton image. For
+ // now it can just be hard-coded.
+ for_each_xml_child_node(partNode, widgetNode)
+ {
+ if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
+ continue;
+
+ std::string partType;
+ partType = XML::getProperty(partNode, "type", "unknown");
+ // TOP ROW
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ if (partType == "top-left-corner")
+ border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "top-edge")
+ border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "top-right-corner")
+ border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
+
+ // MIDDLE ROW
+ else if (partType == "left-edge")
+ border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "bg-quad")
+ border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "right-edge")
+ border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
+
+ // BOTTOM ROW
+ else if (partType == "bottom-left-corner")
+ border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "bottom-edge")
+ border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
+ else if (partType == "bottom-right-corner")
+ border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
+
+ // Part is of an uknown type.
+ else
+ logger->log("SkinLoader::load(): Unknown Part Type '%s'", partType.c_str());
+ }
+ }
+ // Widget is of an uknown type.
+ else
+ {
+ logger->log("SkinLoader::load(): Unknown Widget Type '%s'", widgetType.c_str());
+ }
+ }
+ dBorders->decRef();
+
+ logger->log("Finished loading Skin.");
+
+ // Hard-coded for now until we update the above code to look for window buttons.
+ Image* closeImage = resman->getImage("graphics/gui/close_button.png");
+
+ Skin* skin = new Skin(border, closeImage);
+
+ mSkins[filename] = skin;
+ return skin;
+}
+
+SkinLoader::SkinLoader()
+{
+}
+
+SkinLoader::~SkinLoader()
+{
+ delete_all(mSkins);
+}
+
diff --git a/src/gui/skin.h b/src/gui/skin.h
new file mode 100644
index 00000000..b8a1242e
--- /dev/null
+++ b/src/gui/skin.h
@@ -0,0 +1,101 @@
+/*
+ * Aethyra
+ * Copyright (C) 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SKIN_H
+#define SKIN_H
+
+#include <map>
+#include <string>
+
+#include "../graphics.h"
+
+class Image;
+
+class Skin
+{
+ public:
+ Skin(ImageRect skin, Image* close, std::string name = "");
+ ~Skin();
+
+ /**
+ * Returns the skin's name. Useful for giving a human friendly skin
+ * name if a dialog for skin selection for a specific window type is
+ * done.
+ */
+ std::string getName() { return mName; }
+
+ /**
+ * Returns the background skin.
+ */
+ ImageRect getBorder() { return border; }
+
+ /**
+ * Returns the image used by a close button for this skin.
+ */
+ Image* getCloseImage() { return closeImage; }
+
+ /**
+ * Returns the number of instances which use this skin.
+ */
+ int getNumberOfInstances() { return instances; }
+
+ /**
+ * Returns the minimum width which can be used with this skin.
+ */
+ unsigned int getMinWidth();
+
+ /**
+ * Returns the minimum height which can be used with this skin.
+ */
+ unsigned int getMinHeight();
+
+ int instances;
+
+ private:
+ std::string mName; /**< Name of the skin to use */
+ ImageRect border; /**< The window border and background */
+ Image *closeImage; /**< Close Button Image */
+};
+
+// Map containing all window skins
+typedef std::map<std::string, Skin*> Skins;
+
+// Iterator for window skins
+typedef Skins::iterator SkinIterator;
+
+class SkinLoader
+{
+ public:
+ SkinLoader();
+ ~SkinLoader();
+
+ /**
+ * Loads a skin
+ */
+ Skin* load(const std::string &filename);
+
+ private:
+ Skins mSkins;
+};
+
+extern SkinLoader* skinLoader;
+
+#endif
diff --git a/src/gui/slider.cpp b/src/gui/slider.cpp
index 9bfa840f..cc381c32 100644
--- a/src/gui/slider.cpp
+++ b/src/gui/slider.cpp
@@ -95,6 +95,16 @@ void Slider::init()
vGrip = slider->getSubImage(x, y, w, h);
slider->decRef();
+
+ hStart->setAlpha(mAlpha);
+ hMid->setAlpha(mAlpha);
+ hEnd->setAlpha(mAlpha);
+ hGrip->setAlpha(mAlpha);
+
+ vStart->setAlpha(mAlpha);
+ vMid->setAlpha(mAlpha);
+ vEnd->setAlpha(mAlpha);
+ vGrip->setAlpha(mAlpha);
}
mInstances++;
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
index 165d216f..73ada2e1 100644
--- a/src/gui/speechbubble.cpp
+++ b/src/gui/speechbubble.cpp
@@ -29,14 +29,17 @@
#include "speechbubble.h"
#include "textbox.h"
+#include "../graphics.h"
+
#include "../utils/gettext.h"
SpeechBubble::SpeechBubble():
- Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml")
+ Popup("Speech", NULL, "graphics/gui/speechbubble.xml"),
+ mText("")
{
setContentSize(140, 46);
- setShowTitle(false);
- setTitleBarHeight(0);
+ setMinWidth(29);
+ setMinHeight(29);
mCaption = new gcn::Label("");
mCaption->setFont(boldFont);
@@ -45,6 +48,7 @@ SpeechBubble::SpeechBubble():
mSpeechBox = new TextBox;
mSpeechBox->setEditable(false);
mSpeechBox->setOpaque(false);
+ mSpeechBox->setTextColor(&guiPalette->getColor(Palette::CHAT));
mSpeechArea = new ScrollArea(mSpeechBox);
@@ -56,26 +60,29 @@ SpeechBubble::SpeechBubble():
add(mCaption);
add(mSpeechArea);
-
- setLocationRelativeTo(getParent());
}
-void SpeechBubble::setCaption(const std::string &name, const gcn::Color &color)
+void SpeechBubble::setCaption(const std::string &name, const gcn::Color *color)
{
mCaption->setCaption(name);
mCaption->adjustSize();
- mCaption->setForegroundColor(color);
+ mCaption->setForegroundColor(*color);
}
-void SpeechBubble::setText(std::string mText, bool showName)
+void SpeechBubble::setText(std::string text, bool showName)
{
+ if ((text == mText) && (mCaption->getWidth() <= mSpeechBox->getMinWidth()))
+ return;
+
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
+
int width = mCaption->getWidth();
- mSpeechBox->setTextWrapped(mText, 130 > width ? 130 : width);
+ mSpeechBox->setTextWrapped(text, 130 > width ? 130 : width);
const int fontHeight = getFont()->getHeight();
const int numRows = showName ? mSpeechBox->getNumberOfRows() + 1 :
mSpeechBox->getNumberOfRows();
- int yPos = showName ? fontHeight + 3 : 3;
+ int yPos = showName ? fontHeight + getPadding() : getPadding();
int height = (numRows * fontHeight);
if (width < mSpeechBox->getMinWidth())
@@ -83,11 +90,11 @@ void SpeechBubble::setText(std::string mText, bool showName)
if (numRows == 1)
{
- yPos = (fontHeight / 4) + 3;
+ yPos = (fontHeight / 4) + getPadding();
height = ((3 * fontHeight) / 2) + 1;
}
- setContentSize(width + fontHeight, height + 6);
+ setContentSize(width + fontHeight, height + getPadding());
mSpeechArea->setDimension(gcn::Rectangle(4, yPos, width + 5, height));
}
diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h
index 5d582b1d..3eead884 100644
--- a/src/gui/speechbubble.h
+++ b/src/gui/speechbubble.h
@@ -23,23 +23,44 @@
#ifndef SPEECHBUBBLE_H
#define SPEECHBUBBLE_H
-#include "window.h"
+#include "palette.h"
+#include "popup.h"
class ScrollArea;
class TextBox;
-class SpeechBubble : public Window
+class SpeechBubble : public Popup
{
public:
+ /**
+ * Constructor. Initializes the speech bubble.
+ */
SpeechBubble();
+ /**
+ * Sets the name displayed for the speech bubble, and in what color.
+ */
void setCaption(const std::string &name,
- const gcn::Color &color = 0x000000);
- void setText(std::string mText, bool showName = true);
+ const gcn::Color *color =
+ &guiPalette->getColor(Palette::TEXT));
+
+ /**
+ * Sets the text to be displayed.
+ */
+ void setText(std::string text, bool showName = true);
+
+ /**
+ * Sets the location in which the speech bubble will be displayed.
+ */
void setLocation(int x, int y);
+
+ /**
+ * Gets the number of rows the speech bubble has.
+ */
unsigned int getNumRows();
private:
+ std::string mText;
gcn::Label *mCaption;
TextBox *mSpeechBox;
ScrollArea *mSpeechArea;
diff --git a/src/gui/status.cpp b/src/gui/status.cpp
index 3c48d045..2f95f1c8 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widgets/label.hpp>
-
#include "button.h"
+#include "label.h"
#include "progressbar.h"
#include "status.h"
#include "windowcontainer.h"
@@ -42,28 +41,27 @@ StatusWindow::StatusWindow(LocalPlayer *player):
{
setWindowName("Status");
setCloseButton(true);
- setDefaultSize((windowContainer->getWidth() - 365) / 2,
- (windowContainer->getHeight() - 255) / 2, 400, 345);
+ setDefaultSize(400, 345, ImageRect::CENTER);
// ----------------------
// Status Part
// ----------------------
- mLvlLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
- mJobLvlLabel = new gcn::Label(strprintf(_("Job: %d"), 0));
- mGpLabel = new gcn::Label(strprintf(_("Money: %s"),
+ mLvlLabel = new Label(strprintf(_("Level: %d"), 0));
+ mJobLvlLabel = new Label(strprintf(_("Job: %d"), 0));
+ mGpLabel = new Label(strprintf(_("Money: %s"),
Units::formatCurrency(mCurrency).c_str()));
- mHpLabel = new gcn::Label(_("HP:"));
+ mHpLabel = new Label(_("HP:"));
mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34);
- mXpLabel = new gcn::Label(_("Exp:"));
+ mXpLabel = new Label(_("Exp:"));
mXpBar = new ProgressBar(1.0f, 80, 15, 143, 192, 211);
- mMpLabel = new gcn::Label(_("MP:"));
+ mMpLabel = new Label(_("MP:"));
mMpBar = new ProgressBar(1.0f, 80, 15, 26, 102, 230);
- mJobLabel = new gcn::Label(_("Job:"));
+ mJobLabel = new Label(_("Job:"));
mJobBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203);
// ----------------------
@@ -71,41 +69,41 @@ StatusWindow::StatusWindow(LocalPlayer *player):
// ----------------------
// Static Labels
- gcn::Label *mStatsTitleLabel = new gcn::Label(_("Stats"));
- gcn::Label *mStatsTotalLabel = new gcn::Label(_("Total"));
- gcn::Label *mStatsCostLabel = new gcn::Label(_("Cost"));
+ gcn::Label *mStatsTitleLabel = new Label(_("Stats"));
+ gcn::Label *mStatsTotalLabel = new Label(_("Total"));
+ gcn::Label *mStatsCostLabel = new Label(_("Cost"));
mStatsTotalLabel->setAlignment(gcn::Graphics::CENTER);
// Derived Stats
- mStatsAttackLabel = new gcn::Label(_("Attack:"));
- mStatsDefenseLabel= new gcn::Label(_("Defense:"));
- mStatsMagicAttackLabel = new gcn::Label(_("M.Attack:"));
- mStatsMagicDefenseLabel = new gcn::Label(_("M.Defense:"));
+ mStatsAttackLabel = new Label(_("Attack:"));
+ mStatsDefenseLabel= new Label(_("Defense:"));
+ mStatsMagicAttackLabel = new Label(_("M.Attack:"));
+ mStatsMagicDefenseLabel = new Label(_("M.Defense:"));
// Gettext flag for next line: xgettext:no-c-format
- mStatsAccuracyLabel = new gcn::Label(_("% Accuracy:"));
+ mStatsAccuracyLabel = new Label(_("% Accuracy:"));
// Gettext flag for next line: xgettext:no-c-format
- mStatsEvadeLabel = new gcn::Label(_("% Evade:"));
+ mStatsEvadeLabel = new Label(_("% Evade:"));
// Gettext flag for next line: xgettext:no-c-format
- mStatsReflexLabel = new gcn::Label(_("% Reflex:"));
+ mStatsReflexLabel = new Label(_("% Reflex:"));
- mStatsAttackPoints = new gcn::Label;
- mStatsDefensePoints = new gcn::Label;
- mStatsMagicAttackPoints = new gcn::Label;
- mStatsMagicDefensePoints = new gcn::Label;
- mStatsAccuracyPoints = new gcn::Label;
- mStatsEvadePoints = new gcn::Label;
- mStatsReflexPoints = new gcn::Label;
+ mStatsAttackPoints = new Label;
+ mStatsDefensePoints = new Label;
+ mStatsMagicAttackPoints = new Label;
+ mStatsMagicDefensePoints = new Label;
+ mStatsAccuracyPoints = new Label;
+ mStatsEvadePoints = new Label;
+ mStatsReflexPoints = new Label;
// New labels
for (int i = 0; i < 6; i++)
{
- mStatsLabel[i] = new gcn::Label("0");
+ mStatsLabel[i] = new Label("0");
mStatsLabel[i]->setAlignment(gcn::Graphics::CENTER);
- mStatsDisplayLabel[i] = new gcn::Label;
- mPointsLabel[i] = new gcn::Label("0");
+ mStatsDisplayLabel[i] = new Label;
+ mPointsLabel[i] = new Label("0");
mPointsLabel[i]->setAlignment(gcn::Graphics::CENTER);
}
- mRemainingStatsPointsLabel = new gcn::Label;
+ mRemainingStatsPointsLabel = new Label;
// Set button events Id
mStatsButton[0] = new Button("+", "STR", this);
@@ -181,39 +179,13 @@ void StatusWindow::update()
mGpLabel->adjustSize();
}
- mHpBar->setText(toString(mPlayer->getHp()) +
- "/" + toString(mPlayer->getMaxHp()));
-
- mMpBar->setText(toString(mPlayer->mMp) +
- "/" + toString(mPlayer->mMaxMp));
-
- mXpBar->setText(toString(mPlayer->getXp()) +
- "/" + toString(mPlayer->mXpForNextLevel));
-
- mJobBar->setText(toString(mPlayer->mJobXp) +
- "/" + toString(mPlayer->mJobXpForNextLevel));
+ updateHPBar(mHpBar, true);
- // HP Bar coloration
- if (mPlayer->getHp() < int(mPlayer->getMaxHp() / 3))
- {
- mHpBar->setColor(223, 32, 32); // Red
- }
- else if (mPlayer->getHp() < int((mPlayer->getMaxHp() / 3) * 2))
- {
- mHpBar->setColor(230, 171, 34); // Orange
- }
- else
- {
- mHpBar->setColor(0, 171, 34); // Green
- }
+ updateMPBar(mMpBar, true);
- mHpBar->setProgress((float) mPlayer->getHp() / (float) mPlayer->getMaxHp());
- mMpBar->setProgress((float) mPlayer->mMp / (float) mPlayer->mMaxMp);
+ updateXPBar(mXpBar, false);
- mXpBar->setProgress(
- (float) mPlayer->getXp() / (float) mPlayer->mXpForNextLevel);
- mJobBar->setProgress(
- (float) mPlayer->mJobXp / (float) mPlayer->mJobXpForNextLevel);
+ updateJobBar(mJobBar, false);
// Stats Part
// ----------
@@ -281,6 +253,9 @@ void StatusWindow::update()
void StatusWindow::draw(gcn::Graphics *g)
{
+ if (!isVisible())
+ return;
+
update();
Window::draw(g);
@@ -292,29 +267,97 @@ void StatusWindow::action(const gcn::ActionEvent &event)
if (event.getId().length() == 3)
{
if (event.getId() == "STR")
- {
player_node->raiseAttribute(LocalPlayer::STR);
- }
if (event.getId() == "AGI")
- {
player_node->raiseAttribute(LocalPlayer::AGI);
- }
if (event.getId() == "VIT")
- {
player_node->raiseAttribute(LocalPlayer::VIT);
- }
if (event.getId() == "INT")
- {
player_node->raiseAttribute(LocalPlayer::INT);
- }
if (event.getId() == "DEX")
- {
player_node->raiseAttribute(LocalPlayer::DEX);
- }
if (event.getId() == "LUK")
- {
player_node->raiseAttribute(LocalPlayer::LUK);
+ }
+}
+
+void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
+{
+ if (showMax)
+ bar->setText(toString(player_node->getHp()) +
+ "/" + toString(player_node->getMaxHp()));
+ else
+ bar->setText(toString(player_node->getHp()));
+
+ // HP Bar coloration
+ if (player_node->getHp() < player_node->getMaxHp() / 3)
+ {
+ bar->setColor(223, 32, 32); // Red
+ }
+ else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2)
+ {
+ bar->setColor(230, 171, 34); // Orange
+ }
+ else
+ {
+ bar->setColor(0, 171, 34); // Green
+ }
+
+ bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp());
+}
+
+void StatusWindow::updateMPBar(ProgressBar *bar, bool showMax)
+{
+ if (showMax)
+ bar->setText(toString(player_node->mMp) +
+ "/" + toString(player_node->mMaxMp));
+ else
+ bar->setText(toString(player_node->mMp));
+
+
+ bar->setProgress((float) player_node->mMp / (float) player_node->mMaxMp);
+}
+
+void StatusWindow::updateXPBar(ProgressBar *bar, bool percent)
+{
+ if (player_node->mXpForNextLevel == 0) {
+ bar->setText(_("Max level"));
+ bar->setProgress(1.0);
+ } else {
+ if (percent)
+ {
+ float xp = (float) player_node->getXp() /
+ player_node->mXpForNextLevel;
+ bar->setText(toString((float) ((int) (xp * 10000.0f)) / 100.0f) +
+ "%");
}
+ else
+ bar->setText(toString(player_node->getXp()) +
+ "/" + toString(player_node->mXpForNextLevel));
+
+ bar->setProgress((float) player_node->getXp() /
+ (float) player_node->mXpForNextLevel);
}
}
+void StatusWindow::updateJobBar(ProgressBar *bar, bool percent)
+{
+ if (player_node->mJobXpForNextLevel == 0) {
+ bar->setText(_("Max level"));
+ bar->setProgress(1.0);
+ } else {
+ if (percent)
+ {
+ float xp = (float) player_node->mJobXp /
+ player_node->mJobXpForNextLevel;
+ bar->setText(toString((float) ((int) (xp * 10000.0f)) / 100.0f) +
+ "%");
+ }
+ else
+ bar->setText(toString(player_node->mJobXp) +
+ "/" + toString(player_node->mJobXpForNextLevel));
+
+ bar->setProgress((float) player_node->mJobXp /
+ (float) player_node->mJobXpForNextLevel);
+ }
+}
diff --git a/src/gui/status.h b/src/gui/status.h
index 9e4de3fd..1425fe12 100644
--- a/src/gui/status.h
+++ b/src/gui/status.h
@@ -57,6 +57,11 @@ class StatusWindow : public Window, public gcn::ActionListener
*/
void update();
+ static void updateHPBar(ProgressBar *bar, bool showMax = false);
+ static void updateMPBar(ProgressBar *bar, bool showMax = false);
+ static void updateXPBar(ProgressBar *bar, bool percent = true);
+ static void updateJobBar(ProgressBar *bar, bool percent = true);
+
private:
LocalPlayer *mPlayer;
diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp
index bcac0a90..8d4363d9 100644
--- a/src/gui/statuswindow.cpp
+++ b/src/gui/statuswindow.cpp
@@ -208,28 +208,7 @@ void StatusWindow::update()
mMoneyLabel->setCaption("Money: " + toString(mPlayer->getMoney()) + " GP");
mMoneyLabel->adjustSize();
- int hp = mPlayer->getHp();
- int maxHp = mPlayer->getMaxHp();
-
- mHpValueLabel->setCaption(toString(hp) +
- " / " + toString(maxHp));
- mHpValueLabel->adjustSize();
-
- // HP Bar coloration
- if (hp < int(maxHp / 3))
- {
- mHpBar->setColor(223, 32, 32); // Red
- }
- else if (hp < int((maxHp / 3) * 2))
- {
- mHpBar->setColor(230, 171, 34); // Orange
- }
- else
- {
- mHpBar->setColor(0, 171, 34); // Green
- }
-
- mHpBar->setProgress((float) hp / maxHp);
+ updateHPBar(mHpBar, true);
// Stats Part
// ----------
@@ -368,3 +347,30 @@ void StatusWindow::action(const gcn::ActionEvent &event)
mPlayer->lowerAttribute(LocalPlayer::WIL);
}
}
+
+// WARNING: Duplicated method!
+
+void StatusWindow::updateHPBar(ProgressBar *bar, bool showMax)
+{
+ if (showMax)
+ bar->setText(toString(player_node->getHp()) +
+ "/" + toString(player_node->getMaxHp()));
+ else
+ bar->setText(toString(player_node->getHp()));
+
+ // HP Bar coloration
+ if (player_node->getHp() < player_node->getMaxHp() / 3)
+ {
+ bar->setColor(223, 32, 32); // Red
+ }
+ else if (player_node->getHp() < (player_node->getMaxHp() / 3) * 2)
+ {
+ bar->setColor(230, 171, 34); // Orange
+ }
+ else
+ {
+ bar->setColor(0, 171, 34); // Green
+ }
+
+ bar->setProgress((float) player_node->getHp() / (float) player_node->getMaxHp());
+}
diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h
index 262b89f6..05bac4e5 100644
--- a/src/gui/statuswindow.h
+++ b/src/gui/statuswindow.h
@@ -62,6 +62,8 @@ class StatusWindow : public Window, public gcn::ActionListener
*/
void update();
+ static void updateHPBar(ProgressBar *bar, bool showMax = false);
+
private:
LocalPlayer *mPlayer;
diff --git a/src/gui/storagewindow.cpp b/src/gui/storagewindow.cpp
new file mode 100644
index 00000000..81212ae8
--- /dev/null
+++ b/src/gui/storagewindow.cpp
@@ -0,0 +1,210 @@
+/*
+ * The Mana World
+ * Copyright (C) 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+
+#include <guichan/font.hpp>
+#include <guichan/mouseinput.hpp>
+
+#include "button.h"
+#include "inventorywindow.h"
+#include "item_amount.h"
+#include "itemcontainer.h"
+#include "label.h"
+#include "progressbar.h"
+#include "scrollarea.h"
+#include "storagewindow.h"
+#include "viewport.h"
+
+#include "widgets/layout.h"
+
+#include "../inventory.h"
+#include "../item.h"
+#include "../localplayer.h"
+#include "../units.h"
+
+#include "../net/messageout.h"
+#ifdef EATHENA_SUPPORT
+#include "../net/ea/protocol.h"
+#endif
+
+#include "../resources/iteminfo.h"
+
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+#include "../utils/stringutils.h"
+
+StorageWindow::StorageWindow(Network *network, int invSize):
+ Window(_("Storage")),
+ mNetwork(network),
+ mMaxSlots(invSize),
+ mItemDesc(false)
+{
+ setWindowName("Storage");
+ setResizable(true);
+ setCloseButton(true);
+
+ // If you adjust these defaults, don't forget to adjust the trade window's.
+ setDefaultSize(375, 300, ImageRect::CENTER);
+
+ mStoreButton = new Button(_("Store"), "store", this);
+ mRetrieveButton = new Button(_("Retrieve"), "retrieve", this);
+
+ mItems = new ItemContainer(player_node->getStorage(), 10, 5, 1);
+ mItems->addSelectionListener(this);
+
+ mInvenScroll = new ScrollArea(mItems);
+ mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+
+ mUsedSlots = toString(player_node->getStorage()->getNumberOfSlotsUsed());
+
+ mSlotsLabel = new Label(_("Slots: "));
+
+ mSlotsBar = new ProgressBar(1.0f, 100, 20, 225, 200, 25);
+
+ setMinHeight(130);
+ setMinWidth(mSlotsLabel->getWidth());
+
+ place(0, 0, mSlotsLabel).setPadding(3);
+ place(1, 0, mSlotsBar, 3);
+ place(0, 1, mInvenScroll, 4, 4);
+ place(2, 5, mStoreButton);
+ place(3, 5, mRetrieveButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, mStoreButton->getHeight());
+
+ loadWindowState();
+}
+
+StorageWindow::~StorageWindow()
+{
+ delete mItems;
+}
+
+void StorageWindow::logic()
+{
+ if (!isVisible())
+ return;
+
+ Window::logic();
+
+ if (mUsedSlots != toString(player_node->getStorage()->getNumberOfSlotsUsed()))
+ {
+ mUsedSlots = toString(player_node->getStorage()->getNumberOfSlotsUsed());
+
+ mSlotsBar->setProgress((float)
+ player_node->getStorage()->getNumberOfSlotsUsed() / mMaxSlots);
+
+ mSlotsBar->setText(strprintf("%s/%d", mUsedSlots.c_str(), mMaxSlots));
+ }
+}
+
+void StorageWindow::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "store")
+ {
+ if (!inventoryWindow->isVisible()) return;
+
+ Item *item = inventoryWindow->getSelectedItem();
+
+ if (!item)
+ return;
+
+ if (item->getQuantity() == 1)
+ {
+ addStore(item, 1);
+ }
+ else
+ {
+ // Choose amount of items to trade
+ new ItemAmountWindow(AMOUNT_STORE_ADD, this, item);
+ }
+ }
+ else if (event.getId() == "retrieve")
+ {
+ Item *item = mItems->getSelectedItem();
+
+ if (!item)
+ return;
+
+ if (item->getQuantity() == 1)
+ {
+ removeStore(item, 1);
+ }
+ else
+ {
+ // Choose amount of items to trade
+ new ItemAmountWindow(AMOUNT_STORE_REMOVE, this, item);
+ }
+ }
+}
+
+void StorageWindow::mouseClicked(gcn::MouseEvent &event)
+{
+ Window::mouseClicked(event);
+
+ if (event.getButton() == gcn::MouseEvent::RIGHT)
+ {
+ Item *item = mItems->getSelectedItem();
+
+ if (!item) {
+ mRetrieveButton->setEnabled(false);
+ return;
+ }
+
+ mRetrieveButton->setEnabled(true);
+
+ /* Convert relative to the window coordinates to absolute screen
+ * coordinates.
+ */
+ const int mx = event.getX() + getX();
+ const int my = event.getY() + getY();
+ viewport->showPopup(mx, my, item);
+ }
+}
+
+Item* StorageWindow::getSelectedItem() const
+{
+ return mItems->getSelectedItem();
+}
+
+void StorageWindow::addStore(Item* item, int ammount)
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_MOVE_TO_STORAGE);
+ outMsg.writeInt16(item->getInvIndex());
+ outMsg.writeInt32(ammount);
+}
+
+void StorageWindow::removeStore(Item* item, int ammount)
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CSMG_MOVE_FROM_STORAGE);
+ outMsg.writeInt16(item->getInvIndex());
+ outMsg.writeInt32(ammount);
+}
+
+void StorageWindow::close()
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_CLOSE_STORAGE);
+}
diff --git a/src/gui/storagewindow.h b/src/gui/storagewindow.h
new file mode 100644
index 00000000..c78d33a7
--- /dev/null
+++ b/src/gui/storagewindow.h
@@ -0,0 +1,110 @@
+/*
+ * The Mana World
+ * Copyright (C) 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef STORAGEWINDOW_H
+#define STORAGEWINDOW_H
+
+#include "window.h"
+
+#include "../inventory.h"
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/selectionlistener.hpp>
+
+class Item;
+class ItemContainer;
+class Network;
+class ProgressBar;
+class TextBox;
+
+/**
+ * Storage dialog.
+ *
+ * \ingroup Interface
+ */
+class StorageWindow : public Window, gcn::ActionListener,
+ gcn::SelectionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ StorageWindow(Network *network, int invSize = (STORAGE_SIZE - 1));
+
+ /**
+ * Destructor.
+ */
+ ~StorageWindow();
+
+ /**
+ * Logic (updates buttons and weight information).
+ */
+ void logic();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Returns the selected item.
+ */
+ Item* getSelectedItem() const;
+
+ void mouseClicked(gcn::MouseEvent &event);
+
+ /**
+ * Add the specified ammount of the specified item to storage
+ */
+ void addStore(Item* item, int ammount);
+
+ /**
+ * Remove the specified ammount of the specified item from storage
+ */
+ void removeStore(Item* item, int ammount);
+
+ /**
+ * Closes the Storage Window, as well as telling the server that the
+ * window has been closed.
+ */
+ void close();
+
+ private:
+ Network *mNetwork;
+ ItemContainer *mItems;
+
+ std::string mSlots;
+ std::string mUsedSlots;
+ gcn::Button *mStoreButton, *mRetrieveButton;
+ gcn::ScrollArea *mInvenScroll;
+
+ gcn::Label *mSlotsLabel;
+
+ ProgressBar *mSlotsBar;
+
+ int mMaxSlots;
+
+ bool mItemDesc;
+};
+
+extern StorageWindow *storageWindow;
+
+#endif // STORAGEWINDOW_H
diff --git a/src/gui/table.cpp b/src/gui/table.cpp
index 1fd088ce..ec5b0480 100644
--- a/src/gui/table.cpp
+++ b/src/gui/table.cpp
@@ -23,7 +23,7 @@
#include <guichan/graphics.hpp>
#include <guichan/key.hpp>
-#include "color.h"
+#include "palette.h"
#include "table.h"
#include "../configuration.h"
@@ -98,6 +98,7 @@ GuiTable::GuiTable(TableModel *initial_model, gcn::Color background,
GuiTable::~GuiTable()
{
+ uninstallActionListeners();
delete mModel;
}
@@ -264,7 +265,7 @@ void GuiTable::installActionListeners()
// -- widget ops
void GuiTable::draw(gcn::Graphics* graphics)
{
- if (!mModel)
+ if (!mModel || !isVisible())
return;
if (config.getValue("guialpha", 0.8) != mAlpha)
@@ -272,11 +273,8 @@ void GuiTable::draw(gcn::Graphics* graphics)
if (mOpaque)
{
- const int red = getBackgroundColor().r;
- const int green = getBackgroundColor().g;
- const int blue = getBackgroundColor().b;
- const int alpha = (int)(mAlpha * 255.0f);
- graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->setColor(guiPalette->getColor(Palette::BACKGROUND,
+ (int)(mAlpha * 255.0f)));
graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
}
@@ -321,18 +319,19 @@ void GuiTable::draw(gcn::Graphics* graphics)
widget->setDimension(bounds);
- if (!mLinewiseMode && c == mSelectedColumn && r == mSelectedRow)
+ graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT,
+ (int)(mAlpha * 255.0f)));
+
+ if (mLinewiseMode && r == mSelectedRow && c == 0)
+ {
+ graphics->fillRectangle(gcn::Rectangle(0, y_offset,
+ getWidth(), height));
+ }
+ else if (!mLinewiseMode &&
+ c == mSelectedColumn && r == mSelectedRow)
{
- bool valid;
- const int red =
- (textColor->getColor('H', valid) >> 16) & 0xFF;
- const int green =
- (textColor->getColor('H', valid) >> 8) & 0xFF;
- const int blue = textColor->getColor('H', valid) & 0xFF;
- const int alpha = (int)(mAlpha * 127.0f);
-
- graphics->setColor(gcn::Color(red, green, blue, alpha));
- graphics->fillRectangle(bounds);
+ graphics->fillRectangle(gcn::Rectangle(x_offset, y_offset,
+ width, height));
}
graphics->pushClipArea(bounds);
@@ -343,21 +342,6 @@ void GuiTable::draw(gcn::Graphics* graphics)
x_offset += width;
}
- if (mLinewiseMode && r == mSelectedRow)
- {
- bool valid;
- const int red =
- (textColor->getColor('H', valid) >> 16) & 0xFF;
- const int green =
- (textColor->getColor('H', valid) >> 8) & 0xFF;
- const int blue = textColor->getColor('H', valid) & 0xFF;
- const int alpha = (int)(mAlpha * 127.0f);
-
- graphics->setColor(gcn::Color(red, green, blue, alpha));
- graphics->fillRectangle(gcn::Rectangle(0, y_offset,
- x_offset, height));
- }
-
y_offset += height;
}
@@ -401,25 +385,21 @@ void GuiTable::keyPressed(gcn::KeyEvent& keyEvent)
else if (key.getValue() == gcn::Key::UP)
{
setSelectedRow(mSelectedRow - 1);
-
keyEvent.consume();
}
else if (key.getValue() == gcn::Key::DOWN)
{
setSelectedRow(mSelectedRow + 1);
-
keyEvent.consume();
}
else if (key.getValue() == gcn::Key::LEFT)
{
setSelectedColumn(mSelectedColumn - 1);
-
keyEvent.consume();
}
else if (key.getValue() == gcn::Key::RIGHT)
{
setSelectedColumn(mSelectedColumn + 1);
-
keyEvent.consume();
}
else if (key.getValue() == gcn::Key::HOME)
@@ -459,7 +439,7 @@ void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
{
if (isFocused())
{
- if (getSelectedRow() >= 0 )
+ if (getSelectedRow() > 0 || (getSelectedRow() == 0 && mWrappingEnabled))
{
setSelectedRow(getSelectedRow() - 1);
}
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 2a86d549..10f727e3 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -23,10 +23,11 @@
#include <guichan/font.hpp>
+#include "palette.h"
#include "textbox.h"
-TextBox::TextBox():
- gcn::TextBox()
+TextBox::TextBox() :
+ gcn::TextBox(), mTextColor(&guiPalette->getColor(Palette::TEXT))
{
setOpaque(false);
setFrameSize(0);
@@ -37,52 +38,46 @@ void TextBox::setTextWrapped(const std::string &text, int minDimension)
{
// Make sure parent scroll area sets width of this widget
if (getParent())
- {
getParent()->logic();
- }
// Take the supplied minimum dimension as a starting point and try to beat it
mMinWidth = minDimension;
std::stringstream wrappedStream;
- std::string::size_type newlinePos, lastNewlinePos = 0;
+ std::string::size_type spacePos, newlinePos, lastNewlinePos = 0;
int minWidth = 0;
int xpos;
+ spacePos = text.rfind(" ", text.size());
+
+ if (spacePos != std::string::npos)
+ {
+ const std::string word = text.substr(spacePos + 1);
+ const int length = getFont()->getWidth(word);
+
+ if (length > mMinWidth)
+ mMinWidth = length;
+ }
+
do
{
// Determine next piece of string to wrap
newlinePos = text.find("\n", lastNewlinePos);
if (newlinePos == std::string::npos)
- {
newlinePos = text.size();
- }
std::string line =
text.substr(lastNewlinePos, newlinePos - lastNewlinePos);
- std::string::size_type spacePos, lastSpacePos = 0;
+ std::string::size_type lastSpacePos = 0;
xpos = 0;
- spacePos = text.rfind(" ", text.size());
-
- if (spacePos != std::string::npos)
- {
- const std::string word = text.substr(spacePos + 1);
- const int length = getFont()->getWidth(word);
-
- if (length > mMinWidth)
- mMinWidth = length;
- }
-
do
{
spacePos = line.find(" ", lastSpacePos);
if (spacePos == std::string::npos)
- {
spacePos = line.size();
- }
std::string word =
line.substr(lastSpacePos, spacePos - lastSpacePos);
diff --git a/src/gui/textbox.h b/src/gui/textbox.h
index 10a81fc0..5884e11c 100644
--- a/src/gui/textbox.h
+++ b/src/gui/textbox.h
@@ -39,6 +39,11 @@ class TextBox : public gcn::TextBox
*/
TextBox();
+ inline void setTextColor(const gcn::Color* color)
+ {
+ mTextColor = color;
+ }
+
/**
* Sets the text after wrapping it to the current width of the widget.
*/
@@ -49,8 +54,18 @@ class TextBox : public gcn::TextBox
*/
int getMinWidth() { return mMinWidth; }
+ /**
+ * Draws the text.
+ */
+ inline void draw(gcn::Graphics *graphics)
+ {
+ setForegroundColor(*mTextColor);
+ gcn::TextBox::draw(graphics);
+ }
+
private:
int mMinWidth;
+ const gcn::Color* mTextColor;
};
#endif
diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp
index 99a95a2e..5c6e4f49 100644
--- a/src/gui/textfield.cpp
+++ b/src/gui/textfield.cpp
@@ -21,6 +21,7 @@
#include <guichan/font.hpp>
+#include "palette.h"
#include "sdlinput.h"
#include "textfield.h"
@@ -54,8 +55,10 @@ TextField::TextField(const std::string& text):
int gridy[4] = {0, 3, 28, 31};
int a = 0, x, y;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
skin.grid[a] = textbox->getSubImage(
gridx[x], gridy[y],
gridx[x + 1] - gridx[x] + 1,
@@ -76,20 +79,22 @@ TextField::~TextField()
instances--;
if (instances == 0)
- {
for_each(skin.grid, skin.grid + 9, dtor<Image*>());
- }
}
void TextField::draw(gcn::Graphics *graphics)
{
- if (isFocused()) {
+ if (!isVisible())
+ return;
+
+ if (isFocused())
+ {
drawCaret(graphics,
- getFont()->getWidth(mText.substr(0, mCaretPosition)) -
- mXScroll);
+ getFont()->getWidth(mText.substr(0, mCaretPosition)) -
+ mXScroll);
}
- graphics->setColor(getForegroundColor());
+ graphics->setColor(guiPalette->getColor(Palette::TEXT));
graphics->setFont(getFont());
graphics->drawText(mText, 1 - mXScroll, 1);
@@ -97,9 +102,7 @@ void TextField::draw(gcn::Graphics *graphics)
{
mAlpha = config.getValue("guialpha", 0.8);
for (int a = 0; a < 9; a++)
- {
skin.grid[a]->setAlpha(mAlpha);
- }
}
}
@@ -117,9 +120,8 @@ void TextField::setNumeric(bool numeric)
{
mNumeric = numeric;
if (!numeric)
- {
return;
- }
+
const char *text = mText.c_str();
for (const char *textPtr = text; *textPtr; ++textPtr)
{
@@ -134,18 +136,15 @@ void TextField::setNumeric(bool numeric)
int TextField::getValue() const
{
if (!mNumeric)
- {
return 0;
- }
+
int value = atoi(mText.c_str());
if (value < mMinimum)
- {
return mMinimum;
- }
+
if (value > mMaximum)
- {
return mMaximum;
- }
+
return value;
}
diff --git a/src/gui/textrenderer.h b/src/gui/textrenderer.h
new file mode 100644
index 00000000..b69e72a7
--- /dev/null
+++ b/src/gui/textrenderer.h
@@ -0,0 +1,81 @@
+/*
+ * Text Renderer
+ * Copyright (C) 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TEXT_RENDERER_H
+#define TEXT_RENDERER_H
+
+#include "graphics.h"
+#include "palette.h"
+
+/**
+ * Class for text rendering. Used by the TextParticle, the Text and FlashText
+ * objects and the Preview in the color dialog.
+ */
+class TextRenderer
+{
+ public:
+ /**
+ * Renders a specified text.
+ */
+ static inline void renderText(gcn::Graphics *graphics, const std::string&
+ text, int x, int y, gcn::Graphics::Alignment align,
+ const gcn::Color color, gcn::Font *font, bool outline = false,
+ bool shadow = false, int alpha = 255)
+ {
+ graphics->setFont(font);
+
+ // Text shadow
+ if (shadow)
+ {
+ graphics->setColor(guiPalette->getColor(Palette::SHADOW,
+ alpha / 2));
+ if (outline)
+ {
+ graphics->drawText(text, x + 2, y + 2, align);
+ }
+ else
+ {
+ graphics->drawText(text, x + 1, y + 1, align);
+ }
+ }
+
+ if (outline) {
+/* graphics->setColor(guiPalette->getColor(Palette::OUTLINE,
+ alpha/4));
+ // TODO: Reanable when we can draw it nicely in software mode
+ graphics->drawText(text, x + 2, y + 2, align);
+ graphics->drawText(text, x + 1, y + 2, align);
+ graphics->drawText(text, x + 2, y + 1, align);*/
+
+ // Text outline
+ graphics->setColor(guiPalette->getColor(Palette::OUTLINE, alpha));
+ graphics->drawText(text, x + 1, y, align);
+ graphics->drawText(text, x - 1, y, align);
+ graphics->drawText(text, x, y + 1, align);
+ graphics->drawText(text, x, y - 1, align);
+ }
+
+ graphics->setColor(color);
+ graphics->drawText(text, x, y, align);
+ }
+};
+
+#endif
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 9910f4ce..5be71a6f 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -22,13 +22,13 @@
#include <sstream>
#include <guichan/font.hpp>
-#include <guichan/widgets/label.hpp>
#include "button.h"
#include "chat.h"
#include "inventorywindow.h"
#include "item_amount.h"
#include "itemcontainer.h"
+#include "label.h"
#include "scrollarea.h"
#include "textfield.h"
#include "trade.h"
@@ -59,20 +59,29 @@ TradeWindow::TradeWindow(Network *network):
Window(_("Trade: You")),
#ifdef EATHENA_SUPPORT
mNetwork(network),
-#endif
+ mMyInventory(new Inventory(INVENTORY_SIZE, 2)),
+ mPartnerInventory(new Inventory(INVENTORY_SIZE, 2))
+#else
mMyInventory(new Inventory(INVENTORY_SIZE)),
- mPartnerInventory(new Inventory(INVENTORY_SIZE))
-#ifdef TMWSERV_SUPPORT
- , mStatus(PREPARING)
+ mPartnerInventory(new Inventory(INVENTORY_SIZE)),
+ mStatus(PREPARING)
#endif
{
setWindowName("Trade");
setResizable(true);
- setDefaultSize(115, 197, 332, 209);
+ setCloseButton(true);
+ setDefaultSize(342, 209, ImageRect::CENTER);
+
+ setMinWidth(342);
+ setMinHeight(209);
+
+ std::string longestName = getFont()->getWidth(_("OK")) >
+ getFont()->getWidth(_("Trade")) ?
+ _("OK") : _("Trade");
Button *mAddButton = new Button(_("Add"), "add", this);
#ifdef EATHENA_SUPPORT
- mOkButton = new Button(_("Ok"), "ok", this);
+ mOkButton = new Button(longestName, "ok", this);
#endif
Button *mCancelButton = new Button(_("Cancel"), "cancel", this);
mTradeButton = new Button(_("Propose trade"), "trade", this);
@@ -86,6 +95,7 @@ TradeWindow::TradeWindow(Network *network):
mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 2);
#endif
mMyItemContainer->addSelectionListener(this);
+
ScrollArea *mMyScroll = new ScrollArea(mMyItemContainer);
#ifdef TMWSERV_SUPPORT
@@ -94,10 +104,12 @@ TradeWindow::TradeWindow(Network *network):
mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 2);
#endif
mPartnerItemContainer->addSelectionListener(this);
+
ScrollArea *mPartnerScroll = new ScrollArea(mPartnerItemContainer);
- mMoneyLabel = new gcn::Label(strprintf(_("You get %d GP."), 0));
- gcn::Label *mMoneyLabel2 = new gcn::Label(_("You give:"));
+ mMoneyLabel = new Label(strprintf(_("You get %s."), ""));
+ gcn::Label *mMoneyLabel2 = new Label(_("You give:"));
+
mMoneyField = new TextField;
mMoneyField->setWidth(40);
Button *mMoneyChange = new Button(_("Change"), "money", this);
@@ -114,9 +126,10 @@ TradeWindow::TradeWindow(Network *network):
place(0, 0, mAddButton);
#ifdef EATHENA_SUPPORT
place(1, 0, mOkButton);
-#endif
+#else
place(2, 0, mTradeButton);
place(3, 0, mCancelButton);
+#endif
Layout &layout = getLayout();
layout.extend(0, 2, 2, 1);
layout.setRowHeight(1, Layout::AUTO_SET);
@@ -124,6 +137,10 @@ TradeWindow::TradeWindow(Network *network):
layout.setColWidth(0, Layout::AUTO_SET);
layout.setColWidth(1, Layout::AUTO_SET);
+#ifdef EATHENA_SUPPORT
+ mOkButton->setCaption(_("OK"));
+#endif
+
loadWindowState();
}
@@ -184,7 +201,8 @@ void TradeWindow::reset()
mMyInventory->clear();
mPartnerInventory->clear();
#ifdef EATHENA_SUPPORT
- mTradeButton->setEnabled(false);
+ mOkButton->setCaption(_("OK"));
+ mOkButton->setActionEventId("ok");
mOkButton->setEnabled(true);
mOkOther = false;
mOkMe = false;
@@ -206,11 +224,6 @@ void TradeWindow::receivedOk()
#else
-void TradeWindow::setTradeButton(bool enabled)
-{
- mTradeButton->setEnabled(enabled);
-}
-
void TradeWindow::receivedOk(bool own)
{
if (own)
@@ -218,13 +231,8 @@ void TradeWindow::receivedOk(bool own)
mOkMe = true;
if (mOkOther)
{
- mTradeButton->setEnabled(true);
- mOkButton->setEnabled(false);
- }
- else
- {
- mTradeButton->setEnabled(false);
- mOkButton->setEnabled(false);
+ mOkButton->setCaption(_("Trade"));
+ mOkButton->setActionEventId("trade");
}
}
else
@@ -232,13 +240,8 @@ void TradeWindow::receivedOk(bool own)
mOkOther = true;
if (mOkMe)
{
- mTradeButton->setEnabled(true);
- mOkButton->setEnabled(false);
- }
- else
- {
- mTradeButton->setEnabled(false);
- mOkButton->setEnabled(true);
+ mOkButton->setCaption(_("Trade"));
+ mOkButton->setActionEventId("trade");
}
}
}
@@ -252,6 +255,10 @@ void TradeWindow::tradeItem(Item *item, int quantity)
addItem(item->getId(), true, quantity);
item->increaseQuantity(-quantity);
#else
+ // TODO: Our newer version of eAthena doesn't register this following
+ // function. Detect the actual server version, and re-enable this
+ // for that version only.
+ //addItem(item->getId(), true, quantity, item->isEquipment());
MessageOut outMsg(mNetwork);
outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST);
outMsg.writeInt16(item->getInvIndex());
@@ -291,15 +298,19 @@ void TradeWindow::action(const gcn::ActionEvent &event)
if (event.getId() == "add")
{
+ if (!inventoryWindow->isVisible()) return;
+
if (!item)
return;
if (mMyInventory->getFreeSlot() < 1)
return;
- if (mMyInventory->contains(item)) {
- chatWindow->chatLog("Failed adding item. You can not "
- "overlap one kind of item on the window.", BY_SERVER);
+ if (mMyInventory->contains(item))
+ {
+ chatWindow->chatLog(_("Failed adding item. You can not "
+ "overlap one kind of item on the window."),
+ BY_SERVER);
return;
}
@@ -372,3 +383,13 @@ void TradeWindow::action(const gcn::ActionEvent &event)
}
#endif
}
+
+void TradeWindow::close()
+{
+#ifdef TMWSERV_SUPPORT
+ Net::GameServer::Player::acceptTrade(false);
+#else
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST);
+#endif
+}
diff --git a/src/gui/trade.h b/src/gui/trade.h
index bde0481c..4c215ba6 100644
--- a/src/gui/trade.h
+++ b/src/gui/trade.h
@@ -91,11 +91,6 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
* Increase quantity of an item.
*/
void increaseQuantity(int index, bool own, int quantity);
-
- /**
- * Set trade Button disabled
- */
- void setTradeButton(bool enabled);
#endif
/**
@@ -123,6 +118,12 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
*/
void action(const gcn::ActionEvent &event);
+ /**
+ * Closes the Trade Window, as well as telling the server that the
+ * window has been closed.
+ */
+ void close();
+
private:
#ifdef TMWSERV_SUPPORT
enum Status
@@ -152,6 +153,7 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
gcn::Label *mMoneyLabel;
gcn::Button *mTradeButton;
#ifdef EATHENA_SUPPORT
+ gcn::Button *mAddButton;
gcn::Button *mOkButton;
#endif
gcn::TextField *mMoneyField;
diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp
index 7c72e2f5..b4b839e9 100644
--- a/src/gui/truetypefont.cpp
+++ b/src/gui/truetypefont.cpp
@@ -76,7 +76,7 @@ typedef std::list<TextChunk>::iterator CacheIterator;
static int fontCounter;
-TrueTypeFont::TrueTypeFont(const std::string &filename, int size)
+TrueTypeFont::TrueTypeFont(const std::string &filename, int size, int style)
{
if (fontCounter == 0 && TTF_Init() == -1)
{
@@ -86,6 +86,7 @@ TrueTypeFont::TrueTypeFont(const std::string &filename, int size)
++fontCounter;
mFont = TTF_OpenFont(filename.c_str(), size);
+ TTF_SetFontStyle (mFont, style);
if (!mFont)
{
diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h
index 71b45fd1..1cf6c2c8 100644
--- a/src/gui/truetypefont.h
+++ b/src/gui/truetypefont.h
@@ -26,8 +26,8 @@
#include <string>
#include <guichan/font.hpp>
-#ifndef __APPLE__
-#include <SDL/SDL_ttf.h>
+#ifdef __APPLE__
+#include <SDL_ttf/SDL_ttf.h>
#else
#include <SDL_ttf.h>
#endif
@@ -48,7 +48,7 @@ class TrueTypeFont : public gcn::Font
* @param filename Font filename.
* @param size Font size.
*/
- TrueTypeFont(const std::string &filename, int size);
+ TrueTypeFont(const std::string &filename, int size, int style = 0);
/**
* Destructor.
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index ca41dbda..8c903c28 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -24,13 +24,11 @@
#include <SDL_thread.h>
#include <zlib.h>
-#include <guichan/widgets/label.hpp>
-
-// Curl should be included after Guichan to avoid Windows redefinitions
#include <curl/curl.h>
#include "browserbox.h"
#include "button.h"
+#include "label.h"
#include "progressbar.h"
#include "scrollarea.h"
#include "updatewindow.h"
@@ -109,7 +107,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost,
mBrowserBox = new BrowserBox;
mScrollArea = new ScrollArea(mBrowserBox);
- mLabel = new gcn::Label(_("Connecting..."));
+ mLabel = new Label(_("Connecting..."));
mProgressBar = new ProgressBar(0.0, 310, 20, 168, 116, 31);
mCancelButton = new Button(_("Cancel"), "cancel", this);
mPlayButton = new Button(_("Play"), "play", this);
@@ -131,7 +129,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost,
Layout &layout = getLayout();
layout.setRowHeight(0, Layout::AUTO_SET);
- setLocationRelativeTo(getParent());
+ center();
setVisible(true);
mCancelButton->requestFocus();
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index cbd1f3f7..c840e456 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -44,6 +44,8 @@ extern volatile int tick_time;
Viewport::Viewport():
mMap(0),
+ mMouseX(0),
+ mMouseY(0),
mPixelViewX(0.0f),
mPixelViewY(0.0f),
mTileViewX(0),
@@ -132,19 +134,23 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
{
if (player_x > mPixelViewX + mScrollRadius)
{
- mPixelViewX += (player_x - mPixelViewX - mScrollRadius) / mScrollLaziness;
+ mPixelViewX += (player_x - mPixelViewX - mScrollRadius) /
+ mScrollLaziness;
}
if (player_x < mPixelViewX - mScrollRadius)
{
- mPixelViewX += (player_x - mPixelViewX + mScrollRadius) / mScrollLaziness;
+ mPixelViewX += (player_x - mPixelViewX + mScrollRadius) /
+ mScrollLaziness;
}
if (player_y > mPixelViewY + mScrollRadius)
{
- mPixelViewY += (player_y - mPixelViewY - mScrollRadius) / mScrollLaziness;
+ mPixelViewY += (player_y - mPixelViewY - mScrollRadius) /
+ mScrollLaziness;
}
if (player_y < mPixelViewY - mScrollRadius)
{
- mPixelViewY += (player_y - mPixelViewY + mScrollRadius) / mScrollLaziness;
+ mPixelViewY += (player_y - mPixelViewY + mScrollRadius) /
+ mScrollLaziness;
}
lastTick++;
}
@@ -167,18 +173,14 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight();
if (mMap)
{
- if (mPixelViewX < 0) {
+ if (mPixelViewX < 0)
mPixelViewX = 0;
- }
- if (mPixelViewY < 0) {
+ if (mPixelViewY < 0)
mPixelViewY = 0;
- }
- if (mPixelViewX > viewXmax) {
+ if (mPixelViewX > viewXmax)
mPixelViewX = viewXmax;
- }
- if (mPixelViewY > viewYmax) {
+ if (mPixelViewY > viewYmax)
mPixelViewY = viewYmax;
- }
}
mTileViewX = (int) (mPixelViewX + 16) / 32;
@@ -205,7 +207,6 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
player_node->setName(player_node->getName());
}
-
// Draw text
if (textManager)
{
@@ -216,8 +217,8 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
- (*i)->drawSpeech(-(int) mPixelViewX, -(int) mPixelViewY);
- (*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
+ (*i)->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
+ (*i)->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY);
}
if (miniStatusWindow)
@@ -234,21 +235,20 @@ void Viewport::logic()
if (!mMap || !player_node)
return;
- int mouseX, mouseY;
- Uint8 button = SDL_GetMouseState(&mouseX, &mouseY);
+ Uint8 button = SDL_GetMouseState(&mMouseX, &mMouseY);
if (mPlayerFollowMouse && button & SDL_BUTTON(1) &&
#ifdef TMWSERV_SUPPORT
get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
{
mLocalWalkTime = tick_time;
- player_node->setDestination(mouseX + (int) mPixelViewX,
- mouseY + (int) mPixelViewY);
+ player_node->setDestination(mMouseX + (int) mPixelViewX,
+ mMouseY + (int) mPixelViewY);
#else
mWalkTime != player_node->mWalkTime)
{
- player_node->setDestination(mouseX / 32 + mTileViewX,
- mouseY / 32 + mTileViewY);
+ player_node->setDestination(mMouseX / 32 + mTileViewX,
+ mMouseY / 32 + mTileViewY);
mWalkTime = player_node->mWalkTime;
#endif
}
@@ -257,11 +257,10 @@ void Viewport::logic()
void Viewport::drawDebugPath(Graphics *graphics)
{
// Get the current mouse position
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
+ SDL_GetMouseState(&mMouseX, &mMouseY);
- const int mouseTileX = (mouseX + (int) mPixelViewX) / 32;
- const int mouseTileY = (mouseY + (int) mPixelViewY) / 32;
+ const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32;
+ const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32;
const Vector &playerPos = player_node->getPosition();
Path debugPath = mMap->findPath(
@@ -353,10 +352,12 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
if (being->mAction == Being::DEAD)
break;
- if (player_node->withinAttackRange(being) || keyboard.isKeyActive(keyboard.KEY_ATTACK))
+ if (player_node->withinAttackRange(being) ||
+ keyboard.isKeyActive(keyboard.KEY_ATTACK))
{
player_node->setGotoTarget(being);
- player_node->attack(being, !keyboard.isKeyActive(keyboard.KEY_TARGET));
+ player_node->attack(being,
+ !keyboard.isKeyActive(keyboard.KEY_TARGET));
}
else
{
@@ -403,9 +404,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
20, Being::MONSTER);
if (target)
- {
- player_node->setTarget(target);
- }
+ player_node->setTarget(target);
}
}
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index a097a4ac..c051e5a2 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -124,6 +124,16 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
int getCameraY() const { return (int) mPixelViewY; }
/**
+ * Returns mouse x in pixels.
+ */
+ int getMouseX() const { return mMouseX; }
+
+ /**
+ * Returns mouse y in pixels.
+ */
+ int getMouseY() const { return mMouseY; }
+
+ /**
* Changes viewpoint by relative pixel coordinates.
*/
void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; }
@@ -140,18 +150,20 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
*/
void drawPath(Graphics *graphics, const Path &path);
- Map *mMap; /**< The current map. */
+ Map *mMap; /**< The current map. */
int mScrollRadius;
int mScrollLaziness;
int mScrollCenterOffsetX;
int mScrollCenterOffsetY;
- float mPixelViewX; /**< Current viewpoint in pixels. */
- float mPixelViewY; /**< Current viewpoint in pixels. */
+ int mMouseX; /**< Current mouse position in pixels. */
+ int mMouseY; /**< Current mouse position in pixels. */
+ float mPixelViewX; /**< Current viewpoint in pixels. */
+ float mPixelViewY; /**< Current viewpoint in pixels. */
int mTileViewX; /**< Current viewpoint in tiles. */
int mTileViewY; /**< Current viewpoint in tiles. */
- bool mShowDebugPath; /**< Show a path from player to pointer. */
- bool mVisibleNames; /**< Show target names. */
+ bool mShowDebugPath; /**< Show a path from player to pointer. */
+ bool mVisibleNames; /**< Show target names. */
bool mPlayerFollowMouse;
#ifdef TMWSERV_SUPPORT
@@ -160,11 +172,10 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
int mWalkTime;
#endif
- PopupMenu *mPopupMenu; /**< Popup menu. */
- Being *mSelectedBeing; /**< Current selected being. */
-
+ PopupMenu *mPopupMenu; /**< Popup menu. */
+ Being *mSelectedBeing; /**< Current selected being. */
};
-extern Viewport *viewport; /**< The viewport */
+extern Viewport *viewport; /**< The viewport */
#endif
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
index 92837603..b736591c 100644
--- a/src/gui/widgets/dropdown.cpp
+++ b/src/gui/widgets/dropdown.cpp
@@ -23,8 +23,8 @@
#include "dropdown.h"
-#include "../color.h"
#include "../listbox.h"
+#include "../palette.h"
#include "../scrollarea.h"
#include "../../configuration.h"
@@ -74,12 +74,15 @@ DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea,
int gridy[4] = {0, 3, 28, 31};
int a = 0, x, y;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
- skin.grid[a] = boxBorder->getSubImage(
- gridx[x], gridy[y],
- gridx[x + 1] - gridx[x] + 1,
- gridy[y + 1] - gridy[y] + 1);
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
+ skin.grid[a] = boxBorder->getSubImage(gridx[x], gridy[y],
+ gridx[x + 1] -
+ gridx[x] + 1,
+ gridy[y + 1] -
+ gridy[y] + 1);
skin.grid[a]->setAlpha(mAlpha);
a++;
}
@@ -104,20 +107,22 @@ DropDown::~DropDown()
for_each(skin.grid, skin.grid + 9, dtor<Image*>());
}
+
+ gcn::ListModel *listModel = getListModel();
+ if (listModel) delete listModel;
}
void DropDown::draw(gcn::Graphics* graphics)
{
+ if (!isVisible())
+ return;
+
int h;
if (mDroppedDown)
- {
h = mFoldedUpHeight;
- }
else
- {
h = getHeight();
- }
if (config.getValue("guialpha", 0.8) != mAlpha)
{
@@ -134,27 +139,20 @@ void DropDown::draw(gcn::Graphics* graphics)
}
}
- bool valid;
const int alpha = (int)(mAlpha * 255.0f);
gcn::Color faceColor = getBaseColor();
faceColor.a = alpha;
- gcn::Color highlightColor = textColor->getColor('H', valid);
- highlightColor.a = alpha;
+ const gcn::Color* highlightColor = &guiPalette->getColor(Palette::HIGHLIGHT,
+ alpha);
gcn::Color shadowColor = faceColor - 0x303030;
shadowColor.a = alpha;
if (mOpaque)
{
- int red = getBackgroundColor().r;
- int green = getBackgroundColor().g;
- int blue = getBackgroundColor().b;
- graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->setColor(guiPalette->getColor(Palette::BACKGROUND, alpha));
graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h));
- red = getForegroundColor().r;
- green = getForegroundColor().g;
- blue = getForegroundColor().b;
- graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->setColor(guiPalette->getColor(Palette::TEXT, alpha));
}
graphics->setFont(getFont());
@@ -166,7 +164,7 @@ void DropDown::draw(gcn::Graphics* graphics)
if (isFocused())
{
- graphics->setColor(highlightColor);
+ graphics->setColor(*highlightColor);
graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h));
}
@@ -178,7 +176,7 @@ void DropDown::draw(gcn::Graphics* graphics)
// Draw two lines separating the ListBox with selected
// element view.
- graphics->setColor(highlightColor);
+ graphics->setColor(*highlightColor);
graphics->drawLine(0, h, getWidth(), h);
graphics->setColor(shadowColor);
graphics->drawLine(0, h + 1, getWidth(), h + 1);
diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp
index 21402c89..7a2d9ee8 100644
--- a/src/gui/widgets/tab.cpp
+++ b/src/gui/widgets/tab.cpp
@@ -24,6 +24,8 @@
#include "tab.h"
#include "tabbedarea.h"
+#include "../palette.h"
+
#include "../../configuration.h"
#include "../../graphics.h"
@@ -35,7 +37,7 @@
int Tab::mInstances = 0;
float Tab::mAlpha = config.getValue("guialpha", 0.8);
-enum{
+enum {
TAB_STANDARD, // 0
TAB_HIGHLIGHTED, // 1
TAB_SELECTED, // 2
@@ -94,8 +96,10 @@ void Tab::init()
{
tab[mode] = resman->getImage(data[mode].file);
a = 0;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
tabImg[mode].grid[a] = tab[mode]->getSubImage(
data[x].gridX, data[y].gridY,
data[x + 1].gridX - data[x].gridX + 1,
@@ -121,13 +125,17 @@ void Tab::draw(gcn::Graphics *graphics)
{
mode = TAB_SELECTED;
// if tab is selected, it doesnt need to highlight activity
- mLabel->setForegroundColor(gcn::Color(0, 0, 0));
+ mLabel->setForegroundColor(guiPalette->getColor(Palette::TEXT));
mHighlighted = false;
}
else if (mHighlighted)
{
mode = TAB_HIGHLIGHTED;
- mLabel->setForegroundColor(gcn::Color(255, 0, 0));
+ mLabel->setForegroundColor(guiPalette->getColor(Palette::TAB_HIGHLIGHT));
+ }
+ else
+ {
+ mLabel->setForegroundColor(guiPalette->getColor(Palette::TEXT));
}
}
diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp
index ce11fe69..a8f2b6f0 100644
--- a/src/gui/widgets/tabbedarea.cpp
+++ b/src/gui/widgets/tabbedarea.cpp
@@ -40,9 +40,8 @@ Tab* TabbedArea::getTab(const std::string &name)
while (itr != itr_end)
{
if ((*itr).first->getCaption() == name)
- {
return static_cast<Tab*>((*itr).first);
- }
+
++itr;
}
return NULL;
@@ -51,9 +50,7 @@ Tab* TabbedArea::getTab(const std::string &name)
void TabbedArea::draw(gcn::Graphics *graphics)
{
if (mTabs.empty())
- {
return;
- }
drawChildren(graphics);
}
@@ -64,9 +61,8 @@ gcn::Widget* TabbedArea::getWidget(const std::string &name)
while (itr != itr_end)
{
if ((*itr).first->getCaption() == name)
- {
return (*itr).second;
- }
+
++itr;
}
@@ -91,9 +87,7 @@ void TabbedArea::addTab(Tab *tab, gcn::Widget *widget)
mTabs.push_back(std::pair<Tab*, gcn::Widget*>(tab, widget));
if (!mSelectedTab)
- {
setSelectedTab(tab);
- }
adjustTabPositions();
adjustSize();
@@ -107,15 +101,10 @@ void TabbedArea::removeTab(Tab *tab)
{
int index = getSelectedTabIndex();
- if (index == (int)mTabs.size() - 1
- && mTabs.size() == 1)
- {
+ if (index == (int)mTabs.size() - 1 && mTabs.size() == 1)
tabIndexToBeSelected = -1;
- }
else
- {
tabIndexToBeSelected = index - 1;
- }
}
TabContainer::iterator iter;
diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp
new file mode 100644
index 00000000..01790a67
--- /dev/null
+++ b/src/gui/widgets/textpreview.cpp
@@ -0,0 +1,81 @@
+/*
+ * The Mana World
+ * Copyright (C) 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <typeinfo>
+
+#include "textpreview.h"
+
+#include "../gui.h"
+#include "../palette.h"
+#include "../textrenderer.h"
+#include "../truetypefont.h"
+
+#include "../../configuration.h"
+
+float TextPreview::mAlpha = config.getValue("guialpha", 0.8);
+
+TextPreview::TextPreview(const std::string* text)
+{
+ mText = text;
+ mTextAlpha = false;
+ mFont = gui->getFont();
+ mTextColor = &guiPalette->getColor(Palette::TEXT);
+ mTextBGColor = NULL;
+ mBGColor = &guiPalette->getColor(Palette::BACKGROUND);
+ mOpaque = false;
+}
+
+void TextPreview::draw(gcn::Graphics* graphics)
+{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ int alpha = (int) (mAlpha * 255.0f);
+
+ if (!mTextAlpha)
+ alpha = 255;
+
+ if (mOpaque)
+ {
+ graphics->setColor(gcn::Color((int) mBGColor->r,
+ (int) mBGColor->g,
+ (int) mBGColor->b,
+ (int)(mAlpha * 255.0f)));
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
+ }
+
+ if (mTextBGColor && typeid(*mFont) == typeid(TrueTypeFont))
+ {
+ TrueTypeFont *font = static_cast<TrueTypeFont*>(mFont);
+ int x = font->getWidth(*mText) + 1 + 2 * ((mOutline || mShadow) ? 1 :0);
+ int y = font->getHeight() + 1 + 2 * ((mOutline || mShadow) ? 1 : 0);
+ graphics->setColor(gcn::Color((int) mTextBGColor->r,
+ (int) mTextBGColor->g,
+ (int) mTextBGColor->b,
+ (int)(mAlpha * 255.0f)));
+ graphics->fillRectangle(gcn::Rectangle(1, 1, x, y));
+ }
+
+ TextRenderer::renderText(graphics, *mText, 2, 2, gcn::Graphics::LEFT,
+ gcn::Color(mTextColor->r, mTextColor->g,
+ mTextColor->b, alpha),
+ mFont, mOutline, mShadow, alpha);
+}
diff --git a/src/gui/widgets/textpreview.h b/src/gui/widgets/textpreview.h
new file mode 100644
index 00000000..e7b7db80
--- /dev/null
+++ b/src/gui/widgets/textpreview.h
@@ -0,0 +1,142 @@
+/*
+ * The Mana World
+ * Copyright (C) 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TEXTPREVIEW_H
+#define TEXTPREVIEW_H
+
+#include <guichan/color.hpp>
+#include <guichan/font.hpp>
+#include <guichan/widget.hpp>
+
+/**
+ * Preview widget for particle colors, etc.
+ */
+class TextPreview : public gcn::Widget
+{
+ public:
+ TextPreview(const std::string* text);
+
+ /**
+ * Sets the color the text is printed in.
+ *
+ * @param color the color to set
+ */
+ inline void setTextColor(const gcn::Color* color)
+ {
+ mTextColor = color;
+ }
+
+ /**
+ * Sets the text to use the set alpha value.
+ *
+ * @param alpha whether to use alpha values for the text or not
+ */
+ inline void useTextAlpha(bool alpha)
+ {
+ mTextAlpha = alpha;
+ }
+
+ /**
+ * Sets the color the text background is drawn in. This is only the
+ * rectangle directly behind the text, not to full widget.
+ *
+ * @param color the color to set
+ */
+ inline void setTextBGColor(const gcn::Color* color)
+ {
+ mTextBGColor = color;
+ }
+
+ /**
+ * Sets the background color of the widget.
+ *
+ * @param color the color to set
+ */
+ inline void setBGColor(const gcn::Color* color)
+ {
+ mBGColor = color;
+ }
+
+ /**
+ * Sets the font to render the text in.
+ *
+ * @param font the font to use.
+ */
+ inline void setFont(gcn::Font *font)
+ {
+ mFont = font;
+ }
+
+ /**
+ * Sets whether to use a shadow while rendering.
+ *
+ * @param shadow true, if a shadow is wanted, false else
+ */
+ inline void setShadow(bool shadow)
+ {
+ mShadow = shadow;
+ }
+
+ /**
+ * Sets whether to use an outline while rendering.
+ *
+ * @param outline true, if an outline is wanted, false else
+ */
+ inline void setOutline(bool outline)
+ {
+ mOutline = outline;
+ }
+
+ /**
+ * Widget's draw method. Does the actual job.
+ *
+ * @param graphics graphics to draw into
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Set opacity for this widget (whether or not to show the background
+ * color)
+ *
+ * @param opaque Whether the widget should be opaque or not
+ */
+ void setOpaque(bool opaque) { mOpaque = opaque; }
+
+ /**
+ * Gets opacity for this widget (whether or not the background color
+ * is shown below the widget)
+ */
+ bool isOpaque() { return mOpaque; }
+
+ private:
+ gcn::Font *mFont;
+ const std::string* mText;
+ const gcn::Color* mTextColor;
+ const gcn::Color* mBGColor;
+ const gcn::Color* mTextBGColor;
+ static float mAlpha;
+ bool mTextAlpha;
+ bool mOpaque;
+ bool mShadow;
+ bool mOutline;
+};
+
+#endif
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 58439316..4689c86a 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -26,6 +26,8 @@
#include <guichan/exception.hpp>
#include "gui.h"
+#include "palette.h"
+#include "skin.h"
#include "window.h"
#include "windowcontainer.h"
@@ -37,16 +39,10 @@
#include "../log.h"
#include "../resources/image.h"
-#include "../resources/resourcemanager.h"
-
-#include "../utils/xml.h"
ConfigListener *Window::windowConfigListener = 0;
-WindowContainer *Window::windowContainer = 0;
int Window::instances = 0;
int Window::mouseResize = 0;
-//ImageRect Window::border;
-Image *Window::closeImage = NULL;
bool Window::mAlphaChanged = false;
class WindowConfigListener : public ConfigListener
@@ -70,23 +66,16 @@ Window::Window(const std::string& caption, bool modal, Window *parent, const std
mMinWinWidth(100),
mMinWinHeight(40),
mMaxWinWidth(INT_MAX),
- mMaxWinHeight(INT_MAX),
- mSkin(skin)
+ mMaxWinHeight(INT_MAX)
{
logger->log("Window::Window(\"%s\")", caption.c_str());
if (!windowContainer)
- {
throw GCN_EXCEPTION("Window::Window(): no windowContainer set");
- }
-
- // Loads the skin
- loadSkin(mSkin);
-
- setGuiAlpha();
if (instances == 0)
{
+ skinLoader = new SkinLoader();
windowConfigListener = new WindowConfigListener;
// Send GUI alpha changed for initialization
windowConfigListener->optionChanged("guialpha");
@@ -99,6 +88,11 @@ Window::Window(const std::string& caption, bool modal, Window *parent, const std
setPadding(3);
setTitleBarHeight(20);
+ // Loads the skin
+ mSkin = skinLoader->load(skin);
+
+ setGuiAlpha();
+
// Add this window to the window container
windowContainer->add(this);
@@ -117,21 +111,8 @@ Window::Window(const std::string& caption, bool modal, Window *parent, const std
Window::~Window()
{
logger->log("Window::~Window(\"%s\")", getCaption().c_str());
- const std::string &name = mWindowName;
- // Saving X, Y and Width and Height for resizables in the config
- if (!name.empty())
- {
- config.setValue(name + "WinX", getX());
- config.setValue(name + "WinY", getY());
- config.setValue(name + "Visible", isVisible());
-
- if (mGrip)
- {
- config.setValue(name + "WinWidth", getWidth());
- config.setValue(name + "WinHeight", getHeight());
- }
- }
+ saveWindowState();
delete mLayout;
@@ -142,22 +123,18 @@ Window::~Window()
delete(w);
}
+ removeWidgetListener(this);
+
instances--;
- // Clean up static resources
- for (int i = 0; i < 9; i++)
- {
- delete border.grid[i];
- border.grid[i] = NULL;
- }
+ mSkin->instances--;
if (instances == 0)
{
+ delete skinLoader;
config.removeListener("guialpha", windowConfigListener);
delete windowConfigListener;
windowConfigListener = NULL;
-
- closeImage->decRef();
}
}
@@ -168,14 +145,17 @@ void Window::setWindowContainer(WindowContainer *wc)
void Window::draw(gcn::Graphics *graphics)
{
+ if (!isVisible())
+ return;
+
Graphics *g = static_cast<Graphics*>(graphics);
- g->drawImageRect(0, 0, getWidth(), getHeight(), border);
+ g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
// Draw title
if (mShowTitle)
{
- g->setColor(gcn::Color(0, 0, 0));
+ g->setColor(guiPalette->getColor(Palette::TEXT));
g->setFont(getFont());
g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT);
}
@@ -183,8 +163,8 @@ void Window::draw(gcn::Graphics *graphics)
// Draw Close Button
if (mCloseButton)
{
- g->drawImage(closeImage,
- getWidth() - closeImage->getWidth() - getPadding(),
+ g->drawImage(mSkin->getCloseImage(),
+ getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
getPadding()
);
}
@@ -192,18 +172,29 @@ void Window::draw(gcn::Graphics *graphics)
// Update window alpha values
if (mAlphaChanged)
{
- for_each(border.grid, border.grid + 9,
+ for_each(mSkin->getBorder().grid, mSkin->getBorder().grid + 9,
std::bind2nd(std::mem_fun(&Image::setAlpha),
config.getValue("guialpha", 0.8)));
- closeImage->setAlpha(config.getValue("guialpha", 0.8));
+ mSkin->getCloseImage()->setAlpha(config.getValue("guialpha", 0.8));
}
drawChildren(graphics);
}
void Window::setContentSize(int width, int height)
{
- setSize(width + 2 * getPadding(),
- height + getPadding() + getTitleBarHeight());
+ width = width + 2 * getPadding();
+ height = height + getPadding() + getTitleBarHeight();
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
}
void Window::setLocationRelativeTo(gcn::Widget *widget)
@@ -218,14 +209,61 @@ void Window::setLocationRelativeTo(gcn::Widget *widget)
getY() + (wy + (widget->getHeight() - getHeight()) / 2 - y));
}
+void Window::setLocationRelativeTo(ImageRect::ImagePosition position,
+ int offsetX, int offsetY)
+{
+ if (position == ImageRect::UPPER_LEFT)
+ {
+ }
+ else if (position == ImageRect::UPPER_CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ }
+ else if (position == ImageRect::UPPER_RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ }
+ else if (position == ImageRect::LEFT)
+ {
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ offsetY += (graphics->getHeight() - getHeight()) / 2;
+ }
+ else if (position == ImageRect::LOWER_LEFT)
+ {
+ offsetY += graphics->getHeight() - getHeight();
+ }
+ else if (position == ImageRect::LOWER_CENTER)
+ {
+ offsetX += (graphics->getWidth() - getWidth()) / 2;
+ offsetY += graphics->getHeight() - getHeight();
+ }
+ else if (position == ImageRect::LOWER_RIGHT)
+ {
+ offsetX += graphics->getWidth() - getWidth();
+ offsetY += graphics->getHeight() - getHeight();
+ }
+
+ setPosition(offsetX, offsetY);
+}
+
void Window::setMinWidth(unsigned int width)
{
- mMinWinWidth = width;
+ mMinWinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
}
void Window::setMinHeight(unsigned int height)
{
- mMinWinHeight = height;
+ mMinWinHeight = height > mSkin->getMinHeight() ?
+ height : mSkin->getMinHeight();
}
void Window::setMaxWidth(unsigned int width)
@@ -317,14 +355,14 @@ void Window::mousePressed(gcn::MouseEvent &event)
if (mCloseButton)
{
gcn::Rectangle closeButtonRect(
- getWidth() - closeImage->getWidth() - getPadding(),
+ getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
getPadding(),
- closeImage->getWidth(),
- closeImage->getHeight());
+ mSkin->getCloseImage()->getWidth(),
+ mSkin->getCloseImage()->getHeight());
if (closeButtonRect.isPointInRect(x, y))
{
- setVisible(false);
+ close();
}
}
@@ -333,6 +371,11 @@ void Window::mousePressed(gcn::MouseEvent &event)
}
}
+void Window::close()
+{
+ setVisible(false);
+}
+
void Window::mouseReleased(gcn::MouseEvent &event)
{
if (mGrip && mouseResize)
@@ -388,8 +431,8 @@ void Window::mouseDragged(gcn::MouseEvent &event)
{
int newX = std::max(0, getX());
int newY = std::max(0, getY());
- newX = std::min(windowContainer->getWidth() - getWidth(), newX);
- newY = std::min(windowContainer->getHeight() - getHeight(), newY);
+ newX = std::min(graphics->getWidth() - getWidth(), newX);
+ newY = std::min(graphics->getHeight() - getHeight(), newY);
setPosition(newX, newY);
}
@@ -434,13 +477,13 @@ void Window::mouseDragged(gcn::MouseEvent &event)
newDim.height += newDim.y;
newDim.y = 0;
}
- if (newDim.x + newDim.width > windowContainer->getWidth())
+ if (newDim.x + newDim.width > graphics->getWidth())
{
- newDim.width = windowContainer->getWidth() - newDim.x;
+ newDim.width = graphics->getWidth() - newDim.x;
}
- if (newDim.y + newDim.height > windowContainer->getHeight())
+ if (newDim.y + newDim.height > graphics->getHeight())
{
- newDim.height = windowContainer->getHeight() - newDim.y;
+ newDim.height = graphics->getHeight() - newDim.y;
}
// Update mouse offset when dragging bottom or right border
@@ -469,8 +512,19 @@ void Window::loadWindowState()
if (mGrip)
{
- setSize((int) config.getValue(name + "WinWidth", mDefaultWidth),
- (int) config.getValue(name + "WinHeight", mDefaultHeight));
+ int width = (int) config.getValue(name + "WinWidth", mDefaultWidth);
+ int height = (int) config.getValue(name + "WinHeight", mDefaultHeight);
+
+ if (getMinWidth() > width)
+ width = getMinWidth();
+ else if (getMaxWidth() < width)
+ width = getMaxWidth();
+ if (getMinHeight() > height)
+ height = getMinHeight();
+ else if (getMaxHeight() < height)
+ height = getMaxHeight();
+
+ setSize(width, height);
}
else
{
@@ -478,19 +532,115 @@ void Window::loadWindowState()
}
}
+void Window::saveWindowState()
+{
+ // Saving X, Y and Width and Height for resizables in the config
+ if (!mWindowName.empty() && mWindowName != "window")
+ {
+ config.setValue(mWindowName + "WinX", getX());
+ config.setValue(mWindowName + "WinY", getY());
+ config.setValue(mWindowName + "Visible", isVisible());
+
+ if (mGrip)
+ {
+ if (getMinWidth() > getWidth())
+ setWidth(getMinWidth());
+ else if (getMaxWidth() < getWidth())
+ setWidth(getMaxWidth());
+ if (getMinHeight() > getHeight())
+ setHeight(getMinHeight());
+ else if (getMaxHeight() < getHeight())
+ setHeight(getMaxHeight());
+
+ config.setValue(mWindowName + "WinWidth", getWidth());
+ config.setValue(mWindowName + "WinHeight", getHeight());
+ }
+ }
+}
+
void Window::setDefaultSize(int defaultX, int defaultY,
int defaultWidth, int defaultHeight)
{
+ if (getMinWidth() > defaultWidth)
+ defaultWidth = getMinWidth();
+ else if (getMaxWidth() < defaultWidth)
+ defaultWidth = getMaxWidth();
+ if (getMinHeight() > defaultHeight)
+ defaultHeight = getMinHeight();
+ else if (getMaxHeight() < defaultHeight)
+ defaultHeight = getMaxHeight();
+
mDefaultX = defaultX;
mDefaultY = defaultY;
mDefaultWidth = defaultWidth;
mDefaultHeight = defaultHeight;
}
+void Window::setDefaultSize()
+{
+ mDefaultX = getX();
+ mDefaultY = getY();
+ mDefaultWidth = getWidth();
+ mDefaultHeight = getHeight();
+}
+
+void Window::setDefaultSize(int defaultWidth, int defaultHeight,
+ ImageRect::ImagePosition position,
+ int offsetX, int offsetY)
+{
+ int x = 0, y = 0;
+
+ if (position == ImageRect::UPPER_LEFT)
+ {
+ }
+ else if (position == ImageRect::UPPER_CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ }
+ else if (position == ImageRect::UPPER_RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ }
+ else if (position == ImageRect::LEFT)
+ {
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ y = (graphics->getHeight() - defaultHeight) / 2;
+ }
+ else if (position == ImageRect::LOWER_LEFT)
+ {
+ y = graphics->getHeight() - defaultHeight;
+ }
+ else if (position == ImageRect::LOWER_CENTER)
+ {
+ x = (graphics->getWidth() - defaultWidth) / 2;
+ y = graphics->getHeight() - defaultHeight;
+ }
+ else if (position == ImageRect::LOWER_RIGHT)
+ {
+ x = graphics->getWidth() - defaultWidth;
+ y = graphics->getHeight() - defaultHeight;
+ }
+
+ mDefaultX = x - offsetX;
+ mDefaultY = y - offsetY;
+ mDefaultWidth = defaultWidth;
+ mDefaultHeight = defaultHeight;
+}
+
void Window::resetToDefaultSize()
{
setPosition(mDefaultX, mDefaultY);
setSize(mDefaultWidth, mDefaultHeight);
+ saveWindowState();
}
int Window::getResizeHandles(gcn::MouseEvent &event)
@@ -528,179 +678,16 @@ void Window::setGuiAlpha()
for (int i = 0; i < 9; i++)
{
//logger->log("Window::setGuiAlpha: Border Image (%i)", i);
- border.grid[i]->setAlpha(config.getValue("guialpha", 0.8));
+ mSkin->getBorder().grid[i]->setAlpha(config.getValue("guialpha", 0.8));
}
mAlphaChanged = false;
}
-void Window::loadSkin(const std::string &fileName)
+int Window::getGuiAlpha()
{
- const std::string windowId = Window::getId();
-
- ResourceManager *resman = ResourceManager::getInstance();
-
- logger->log("Loading Window Skin '%s'.", fileName.c_str());
- logger->log("Loading Window ID '%s'.", windowId.c_str());
-
-
- if (fileName.empty())
- logger->error("Window::loadSkin(): Invalid File Name.");
-
- // TODO:
- // If there is an error loading the specified file, we should try to revert
- // to a 'default' skin file. Only if the 'default' skin file can't be loaded
- // should we have a terminating error.
- XML::Document doc(fileName);
- xmlNodePtr rootNode = doc.rootNode();
-
- if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
- {
- logger->error("Widget Skinning error");
- }
-
- std::string skinSetImage;
- skinSetImage = XML::getProperty(rootNode, "image", "");
- Image *dBorders = NULL;
- if (!skinSetImage.empty())
- {
- logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str());
- dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png");
- }
- else
- {
- logger->error("Window::loadSkin(): Skinset does not define an image!");
- }
-
- //iterate <widget>'s
- for_each_xml_child_node(widgetNode, rootNode)
- {
- if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
- continue;
-
- std::string widgetType;
- widgetType = XML::getProperty(widgetNode, "type", "unknown");
- if (widgetType == "Window")
- {
- // Iterate through <part>'s
- // LEEOR / TODO:
- // We need to make provisions to load in a CloseButton image. For now it
- // can just be hard-coded.
- for_each_xml_child_node(partNode, widgetNode)
- {
- if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
- {
- continue;
- }
-
- std::string partType;
- partType = XML::getProperty(partNode, "type", "unknown");
- // TOP ROW
- if (partType == "top-left-corner")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "top-edge")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "top-right-corner")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
- }
-
- // MIDDLE ROW
- else if (partType == "left-edge")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "bg-quad")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "right-edge")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
- }
-
- // BOTTOM ROW
- else if (partType == "bottom-left-corner")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "bottom-edge")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
- }
- else if (partType == "bottom-right-corner")
- {
- const int xPos = XML::getProperty(partNode, "xpos", 0);
- const int yPos = XML::getProperty(partNode, "ypos", 0);
- const int width = XML::getProperty(partNode, "width", 1);
- const int height = XML::getProperty(partNode, "height", 1);
-
- border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
- }
-
- // Part is of an uknown type.
- else
- {
- logger->log("Window::loadSkin(): Unknown Part Type '%s'", partType.c_str());
- }
- }
- }
- // Widget is of an uknown type.
- else
- {
- logger->log("Window::loadSkin(): Unknown Widget Type '%s'", widgetType.c_str());
- }
- }
- dBorders->decRef();
-
- logger->log("Finished loading Window Skin.");
-
- // Hard-coded for now until we update the above code to look for window buttons.
- closeImage = resman->getImage("graphics/gui/close_button.png");
+ float alpha = config.getValue("guialpha", 0.8);
+ return (int) (alpha * 255.0f);
}
Layout &Window::getLayout()
@@ -728,3 +715,8 @@ void Window::reflowLayout(int w, int h)
mLayout = NULL;
setContentSize(w, h);
}
+
+void Window::center()
+{
+ setLocationRelativeTo(getParent());
+}
diff --git a/src/gui/window.h b/src/gui/window.h
index 3806342a..7f15e262 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -31,11 +31,11 @@
class ConfigListener;
class ContainerPlacer;
-class Image;
-class ImageRect;
class Layout;
class LayoutCell;
class ResizeGrip;
+class Skin;
+class SkinLoader;
class WindowContainer;
/**
@@ -61,7 +61,7 @@ class Window : public gcn::Window, gcn::WidgetListener
* @param skin The location where the window's skin XML can be found.
*/
Window(const std::string &caption = "Window", bool modal = false,
- Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml");
+ Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml");
/**
* Destructor. Deletes all the added widgets.
@@ -89,6 +89,12 @@ class Window : public gcn::Window, gcn::WidgetListener
void setLocationRelativeTo(gcn::Widget *widget);
/**
+ * Sets the location relative to the given enumerated position.
+ */
+ void setLocationRelativeTo(ImageRect::ImagePosition position,
+ int offsetX = 0, int offsetY = 0);
+
+ /**
* Sets whether or not the window can be resized.
*/
void setResizable(bool resize);
@@ -151,8 +157,7 @@ class Window : public gcn::Window, gcn::WidgetListener
/**
* Sets flag to show a title or not.
*/
- void setShowTitle(bool flag)
- { mShowTitle = flag; }
+ void setShowTitle(bool flag) { mShowTitle = flag; }
/**
* Sets whether the window is sticky. A sticky window will not have
@@ -233,6 +238,12 @@ class Window : public gcn::Window, gcn::WidgetListener
void loadWindowState();
/**
+ * Saves the window state so that when the window is reloaded, it'll
+ * maintain its previous state and location.
+ */
+ void saveWindowState();
+
+ /**
* Set the default win pos and size.
* (which can be different of the actual ones.)
*/
@@ -240,10 +251,25 @@ class Window : public gcn::Window, gcn::WidgetListener
int defaultWidth, int defaultHeight);
/**
+ * Set the default win pos and size tot he current ones.
+ */
+ void setDefaultSize();
+
+ /**
+ * Set the default win pos and size.
+ * (which can be different of the actual ones.)
+ * This version of setDefaultSize sets the window's position based
+ * on a relative enumerated position, rather than a coordinate position.
+ */
+ void setDefaultSize(int defaultWidth, int defaultHeight,
+ ImageRect::ImagePosition position,
+ int offsetx = 0, int offsetY = 0);
+
+ /**
* Reset the win pos and size to default. Don't forget to set defaults
* first.
*/
- void resetToDefaultSize();
+ virtual void resetToDefaultSize();
/**
* Gets the layout handler for this window.
@@ -261,11 +287,6 @@ class Window : public gcn::Window, gcn::WidgetListener
void reflowLayout(int w = 0, int h = 0);
/**
- * Loads a window skin
- */
- void loadSkin(const std::string &fileName);
-
- /**
* Adds a widget to the window and sets it at given cell.
*/
LayoutCell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1);
@@ -275,9 +296,22 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
ContainerPlacer getPlacer(int x, int y);
- protected:
- /** The window container windows add themselves to. */
- static WindowContainer *windowContainer;
+ /**
+ * Positions the window in the center of it's parent.
+ */
+ void center();
+
+ /**
+ * Overrideable functionality for when the window is to close. This
+ * allows for class implementations to clean up or do certain actions
+ * on window close they couldn't do otherwise.
+ */
+ virtual void close();
+
+ /**
+ * Gets the alpha value used by the window, in a GUIChan usable format.
+ */
+ int getGuiAlpha();
private:
enum ResizeHandles
@@ -316,7 +350,6 @@ class Window : public gcn::Window, gcn::WidgetListener
int mDefaultY; /**< Default window Y position */
int mDefaultWidth; /**< Default window width */
int mDefaultHeight; /**< Default window height */
- std::string mSkin; /**< Name of the skin to use */
/**
* The config listener that listens to changes relevant to all windows.
@@ -325,8 +358,8 @@ class Window : public gcn::Window, gcn::WidgetListener
static int mouseResize; /**< Active resize handles */
static int instances; /**< Number of Window instances */
- ImageRect border; /**< The window border and background */
- static Image *closeImage; /**< Close Button Image */
+
+ Skin* mSkin; /**< Skin in use by this window */
/**
* The width of the resize border. Is independent of the actual window
diff --git a/src/gui/windowcontainer.cpp b/src/gui/windowcontainer.cpp
index 2846b1c1..eda739b9 100644
--- a/src/gui/windowcontainer.cpp
+++ b/src/gui/windowcontainer.cpp
@@ -23,6 +23,8 @@
#include "../utils/dtor.h"
+WindowContainer *windowContainer = NULL;
+
void WindowContainer::logic()
{
delete_all(mDeathList);
diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h
index 62704d1b..bc918184 100644
--- a/src/gui/windowcontainer.h
+++ b/src/gui/windowcontainer.h
@@ -45,6 +45,11 @@ class WindowContainer : public gcn::Container
*/
void scheduleDelete(gcn::Widget *widget);
+ /**
+ * Get the number of widget instances
+ */
+ int getNumberOfInstances() { return mDeathList.size(); }
+
private:
/**
* List of widgets that are scheduled to be deleted.
@@ -54,4 +59,6 @@ class WindowContainer : public gcn::Container
Widgets mDeathList;
};
+extern WindowContainer* windowContainer;
+
#endif
diff --git a/src/inventory.cpp b/src/inventory.cpp
index cdd7b61c..80bc582b 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -37,8 +37,9 @@ struct SlotUsed : public std::unary_function<Item*, bool>
}
};
-Inventory::Inventory(int size):
- mSize(size)
+Inventory::Inventory(int size, int offset):
+ mSize(size),
+ mOffset(offset)
{
mItems = new Item*[mSize];
std::fill_n(mItems, mSize, (Item*) 0);
@@ -134,11 +135,7 @@ bool Inventory::contains(Item *item) const
int Inventory::getFreeSlot() const
{
-#ifdef TMWSERV_SUPPORT
- Item **i = std::find_if(mItems, mItems + mSize,
-#else
- Item **i = std::find_if(mItems + 2, mItems + mSize,
-#endif
+ Item **i = std::find_if(mItems + mOffset, mItems + mSize,
std::not1(SlotUsed()));
return (i == mItems + mSize) ? -1 : (i - mItems);
}
@@ -156,3 +153,8 @@ int Inventory::getLastUsedSlot() const
return -1;
}
+
+int Inventory::getInventorySize() const
+{
+ return mSize - mOffset;
+}
diff --git a/src/inventory.h b/src/inventory.h
index d2a81edf..008b7ec4 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -24,13 +24,20 @@
class Item;
+#ifdef EATHENA_SUPPORT
+#define INVENTORY_SIZE 102
+#define STORAGE_SIZE 301
+#else
+#define INVENTORY_SIZE 50
+#endif
+
class Inventory
{
public:
/**
* Constructor.
*/
- Inventory(int size);
+ Inventory(int size, int offset = 0);
/**
* Destructor.
@@ -100,10 +107,16 @@ class Inventory
*/
int getLastUsedSlot() const;
+ /**
+ * Returns the number of slots available in the inventory.
+ */
+ int getInventorySize() const;
+
static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */
protected:
Item **mItems; /**< The holder of items */
int mSize; /**< The max number of inventory items */
+ int mOffset; /**< Offset used by the inventory */
};
#endif
diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp
index 73c0fe0a..06ce4ac7 100644
--- a/src/keyboardconfig.cpp
+++ b/src/keyboardconfig.cpp
@@ -197,6 +197,7 @@ int KeyboardConfig::getKeyEmoteOffset(int keyValue) const
bool KeyboardConfig::isKeyActive(int index)
{
+ if (!mActiveKeys) return false;
return mActiveKeys[mKey[index].value];
}
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index c0da92ac..2233942d 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -38,6 +38,10 @@
#include "gui/gui.h"
#include "gui/ministatus.h"
+#include "gui/palette.h"
+#ifdef EATHENA_SUPPORT
+#include "gui/storagewindow.h"
+#endif
#ifdef TMWSERV_SUPPORT
#include "effectmanager.h"
@@ -111,12 +115,11 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
mDestX(0), mDestY(0),
#ifdef TMWSERV_SUPPORT
mLocalWalkTime(-1),
-#endif
- mInventory(new Inventory(INVENTORY_SIZE))
-#ifdef EATHENA_SUPPORT
- , mStorage(new Inventory(STORAGE_SIZE))
+ mInventory(new Inventory(INVENTORY_SIZE)),
+ mExpMessageTime(0)
#else
- , mExpMessageTime(0)
+ mInventory(new Inventory(INVENTORY_SIZE, 2)),
+ mStorage(new Inventory(STORAGE_SIZE, 1))
#endif
{
// Variable to keep the local player from doing certain actions before a map
@@ -148,7 +151,8 @@ LocalPlayer::~LocalPlayer()
void LocalPlayer::logic()
{
#ifdef EATHENA_SUPPORT
- switch (mAction) {
+ switch (mAction)
+ {
case STAND:
break;
@@ -168,13 +172,36 @@ void LocalPlayer::logic()
break;
case ATTACK:
+ int rotation = 0;
+ std::string particleEffect = "";
int frames = 4;
+
if (mEquippedWeapon &&
mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW)
frames = 5;
mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
+ //attack particle effect
+ if (mEquippedWeapon)
+ particleEffect = mEquippedWeapon->getParticleEffect();
+
+ if (!particleEffect.empty() && mParticleEffects && mFrame == 1)
+ {
+ switch (mDirection)
+ {
+ case DOWN: rotation = 0; break;
+ case LEFT: rotation = 90; break;
+ case UP: rotation = 180; break;
+ case RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect("graphics/particles/" +
+ particleEffect, 0, 0, rotation);
+ controlParticle(p);
+ }
+
if (mFrame >= frames)
nextStep();
@@ -193,11 +220,14 @@ void LocalPlayer::logic()
if (mExpMessageTime == 0)
{
const Vector &pos = getPosition();
- particleEngine->addTextRiseFadeOutEffect(mExpMessages.front(),
- 0, 128, 255,
- gui->getFont(),
- (int) pos.x + 16,
- (int) pos.y - 16);
+
+ particleEngine->addTextRiseFadeOutEffect(
+ mExpMessages.front(),
+ (int) pos.x + 16,
+ (int) pos.y - 16,
+ &guiPalette->getColor(Palette::EXP_INFO),
+ gui->getInfoParticleFont(), true);
+
mExpMessages.pop_front();
mExpMessageTime = 30;
}
@@ -218,20 +248,30 @@ void LocalPlayer::logic()
if (mTarget)
{
- // Find whether target is in range
- const int rangeX = abs(mTarget->mX - mX);
- const int rangeY = abs(mTarget->mY - mY);
- const int attackRange = getAttackRange();
- const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0;
+ if (mTarget->getType() == Being::NPC)
+ {
+ // NPCs are always in range
+ mTarget->setTargetAnimation(
+ mTargetCursor[0][mTarget->getTargetCursorSize()]);
+ }
+ else
+ {
+ // Find whether target is in range
+ const int rangeX = abs(mTarget->mX - mX);
+ const int rangeY = abs(mTarget->mY - mY);
+ const int attackRange = getAttackRange();
+ const int inRange = rangeX > attackRange || rangeY > attackRange
+ ? 1 : 0;
- mTarget->setTargetAnimation(
- mTargetCursor[inRange][mTarget->getTargetCursorSize()]);
+ mTarget->setTargetAnimation(
+ mTargetCursor[inRange][mTarget->getTargetCursorSize()]);
- if (mTarget->mAction == DEAD)
- stopAttack();
+ if (mTarget->mAction == DEAD)
+ stopAttack();
- if (mKeepAttacking && mTarget)
- attack(mTarget, true);
+ if (mKeepAttacking && mTarget)
+ attack(mTarget, true);
+ }
}
#endif
@@ -241,7 +281,9 @@ void LocalPlayer::logic()
void LocalPlayer::setGM()
{
mIsGM = !mIsGM;
- mNameColor = mIsGM ? 0x009000: 0x202020;
+ mNameColor = mIsGM ?
+ &guiPalette->getColor(Palette::GM) :
+ &guiPalette->getColor(Palette::PLAYER);
setName(getName());
config.setValue(getName() + "GMassert", mIsGM);
}
@@ -871,7 +913,7 @@ void LocalPlayer::attack(Being *target, bool keep)
{
mKeepAttacking = keep;
- if (!target)
+ if (!target || target->getType() == Being::NPC)
return;
if ((mTarget != target) || !mTarget)
@@ -883,10 +925,8 @@ void LocalPlayer::attack(Being *target, bool keep)
int dist_x = target->mX - mX;
int dist_y = target->mY - mY;
- // Must be standing and be within attack range to continue
- if ((mAction != STAND) || (mAttackRange < abs(dist_x)) ||
- (mAttackRange < abs(dist_y)))
- return;
+ // Must be standing to attack
+ if (mAction != STAND) return;
if (abs(dist_y) >= abs(dist_x))
{
@@ -1030,16 +1070,26 @@ void LocalPlayer::setXp(int xp)
const std::string text = toString(xp - mXp) + " xp";
// Show XP number
- particleEngine->addTextRiseFadeOutEffect(text,
- 255, 255, 0,
- hitYellowFont,
- mPx + 16, mPy - 16);
+ particleEngine->addTextRiseFadeOutEffect(text, mPx + 16, mPy - 16,
+ &guiPalette->getColor(Palette::EXP_INFO),
+ gui->getInfoParticleFont(), true);
}
mXp = xp;
}
#endif
+void LocalPlayer::pickedUp(std::string item)
+{
+ if (mMap)
+ {
+ // Show pickup notification
+ particleEngine->addTextRiseFadeOutEffect(item, mPx + 16, mPy - 16,
+ &guiPalette->getColor(Palette::PICKUP_INFO),
+ gui->getInfoParticleFont (), true);
+ }
+}
+
int LocalPlayer::getAttackRange()
{
#ifdef TMWSERV_SUPPORT
@@ -1181,3 +1231,11 @@ void LocalPlayer::loadTargetCursor(std::string filename, int width, int height,
mTargetCursor[index][size] = currentCursor;
}
+#ifdef EATHENA_SUPPORT
+void LocalPlayer::setInStorage(bool inStorage)
+{
+ mInStorage = inStorage;
+
+ storageWindow->setVisible(inStorage);
+}
+#endif
diff --git a/src/localplayer.h b/src/localplayer.h
index 7ced3fdf..703dbbfa 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -27,16 +27,6 @@
#include "player.h"
-#ifdef EATHENA_SUPPORT
-// TODO move into some sane place...
-#define MAX_SLOT 2
-
-#define INVENTORY_SIZE 102
-#define STORAGE_SIZE 301
-#else
-#define INVENTORY_SIZE 50
-#endif
-
class Equipment;
class FloorItem;
class ImageSet;
@@ -300,10 +290,11 @@ class LocalPlayer : public Player
* displayed as soon as the player attacks, not when the server says
* the player does.
*
- * @param victim The attacked being.
- * @param damage The amount of damage dealt (0 means miss).
+ * @param victim the victim being
+ * @param damage the amount of damage dealt (0 means miss)
+ * @param type the attack type
*/
- virtual void handleAttack(Being *victim, int damage) {}
+ virtual void handleAttack(Being *victim, int damage, AttackType type) {}
virtual void handleAttack() {}
/**
@@ -374,12 +365,17 @@ class LocalPlayer : public Player
void revive();
+ /**
+ * Shows item pickup effect if the player is on a map.
+ */
+ void pickedUp(std::string item);
+
#ifdef EATHENA_SUPPORT
/**
* Accessors for mInStorage
*/
bool getInStorage() { return mInStorage; }
- void setInStorage(bool inStorage) { mInStorage = inStorage; }
+ void setInStorage(bool inStorage);
/**
* Sets the amount of XP. Shows XP gaining effect if the player is on
@@ -404,8 +400,8 @@ class LocalPlayer : public Player
Uint8 mAttr[6];
Uint8 mAttrUp[6];
- Sint16 ATK, MATK, DEF, MDEF, HIT, FLEE;
- Sint16 ATK_BONUS, MATK_BONUS, DEF_BONUS, MDEF_BONUS, FLEE_BONUS;
+ int ATK, MATK, DEF, MDEF, HIT, FLEE;
+ int ATK_BONUS, MATK_BONUS, DEF_BONUS, MDEF_BONUS, FLEE_BONUS;
Uint16 mStatPoint, mSkillPoint;
Uint16 mStatsPointsToAttribute;
diff --git a/src/main.cpp b/src/main.cpp
index 22607e4e..b7afd93e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,7 +27,6 @@
#include <SDL_image.h>
#include <guichan/actionlistener.hpp>
-#include <guichan/widgets/label.hpp>
#include <libxml/parser.h>
@@ -50,6 +49,7 @@
#include "player_relations.h"
#include "serverinfo.h"
#include "sound.h"
+#include "statuseffect.h"
#include "units.h"
#include "gui/button.h"
@@ -57,10 +57,11 @@
#include "gui/char_server.h"
#endif
#include "gui/char_select.h"
-#include "gui/color.h"
#include "gui/gui.h"
+#include "gui/label.h"
#include "gui/login.h"
#include "gui/ok_dialog.h"
+#include "gui/palette.h"
#include "gui/progressbar.h"
#include "gui/register.h"
#include "gui/sdlinput.h"
@@ -128,8 +129,6 @@
namespace
{
- Window *setupWindow = 0;
-
struct SetupListener : public gcn::ActionListener
{
/**
@@ -177,7 +176,7 @@ LogoutHandler logoutHandler;
#endif
LockedArray<LocalPlayer*> charInfo(maxSlot + 1);
-Color *textColor;
+Palette *guiPalette;
// This anonymous namespace hides whatever is inside from other modules.
namespace {
@@ -191,6 +190,8 @@ LoginHandler loginHandler;
MapLoginHandler mapLoginHandler;
#endif
+SDL_Surface *icon;
+
/**
* A structure holding the values of various options that can be passed from
* the command line.
@@ -454,7 +455,7 @@ void initEngine(const Options &options)
SetClassLong(pInfo.window, GCL_HICON, (LONG) icon);
}
#else
- SDL_Surface *icon = IMG_Load(resman->getPath(branding.getValue("appIcon", "data/icons/tmw.png")).c_str());
+ icon = IMG_Load(resman->getPath(branding.getValue("appIcon", "data/icons/tmw.png")).c_str());
if (icon)
{
SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
@@ -507,16 +508,18 @@ void initEngine(const Options &options)
#endif
// Initialize sound engine
- try {
- if (config.getValue("sound", 0) == 1) {
+ try
+ {
+ if (config.getValue("sound", 0) == 1)
sound.init();
- }
+
sound.setSfxVolume((int) config.getValue("sfxVolume",
defaultSfxVolume));
sound.setMusicVolume((int) config.getValue("musicVolume",
defaultMusicVolume));
}
- catch (const char *err) {
+ catch (const char *err)
+ {
state = STATE_ERROR;
errorMessage = err;
logger->log("Warning: %s", err);
@@ -553,8 +556,11 @@ void exit_engine()
ItemDB::unload();
MonsterDB::unload();
NPCDB::unload();
+ StatusEffect::unload();
ResourceManager::deleteInstance();
+
+ SDL_FreeSurface(icon);
}
void printHelp()
@@ -667,6 +673,7 @@ void parseOptions(int argc, char *argv[], Options &options)
*/
void loadUpdates()
{
+ if (updatesDir.empty()) return;
const std::string updatesFile = "/" + updatesDir + "/resources2.txt";
ResourceManager *resman = ResourceManager::getInstance();
std::vector<std::string> lines = resman->loadTextFile(updatesFile);
@@ -1054,7 +1061,7 @@ int main(int argc, char *argv[])
initEngine(options);
// Needs to be created in main, as the updater uses it
- textColor = new Color;
+ guiPalette = new Palette;
Game *game = NULL;
Window *currentDialog = NULL;
@@ -1067,14 +1074,14 @@ int main(int argc, char *argv[])
gcn::Container *top = static_cast<gcn::Container*>(gui->getTop());
#ifdef PACKAGE_VERSION
#ifdef TMWSERV_SUPPORT
- gcn::Label *versionLabel = new gcn::Label(strprintf("%s TMWserv", PACKAGE_VERSION));
+ gcn::Label *versionLabel = new Label(strprintf("%s TMWserv", PACKAGE_VERSION));
#else
- gcn::Label *versionLabel = new gcn::Label(strprintf("%s eAthena", PACKAGE_VERSION));
+ gcn::Label *versionLabel = new Label(strprintf("%s eAthena", PACKAGE_VERSION));
#endif
top->add(versionLabel, 25, 2);
#endif
ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20, 168, 116, 31);
- gcn::Label *progressLabel = new gcn::Label();
+ gcn::Label *progressLabel = new Label();
top->add(progressBar, 5, top->getHeight() - 5 - progressBar->getHeight());
top->add(progressLabel, 15 + progressBar->getWidth(),
progressBar->getY() + 4);
@@ -1180,13 +1187,9 @@ int main(int argc, char *argv[])
{
#ifdef TMWSERV_SUPPORT
if (!quitDialog)
- {
quitDialog = new QuitDialog(NULL, &quitDialog);
- }
else
- {
quitDialog->requestMoveToTop();
- }
#else
state = STATE_EXIT;
#endif
@@ -1210,11 +1213,10 @@ int main(int argc, char *argv[])
{
state = STATE_ERROR;
- if (!network->getError().empty()) {
+ if (!network->getError().empty())
errorMessage = network->getError();
- } else {
+ else
errorMessage = _("Got disconnected from server!");
- }
}
#endif
@@ -1264,10 +1266,9 @@ int main(int argc, char *argv[])
reconnectAccount(token);
state = STATE_WAIT;
}
-#endif
-#ifdef TMWSERV_SUPPORT
- if (state != oldstate) {
+ if (state != oldstate)
+ {
// Load updates after exiting the update state
if (oldstate == STATE_UPDATE)
{
@@ -1548,7 +1549,8 @@ int main(int argc, char *argv[])
#else // no TMWSERV_SUPPORT
- if (state != oldstate) {
+ if (state != oldstate)
+ {
switch (oldstate)
{
case STATE_UPDATE:
@@ -1579,12 +1581,14 @@ int main(int argc, char *argv[])
oldstate = state;
if (currentDialog && state != STATE_ACCOUNT &&
- state != STATE_CHAR_CONNECT) {
+ state != STATE_CHAR_CONNECT)
+ {
delete currentDialog;
currentDialog = NULL;
}
- switch (state) {
+ switch (state)
+ {
case STATE_LOADDATA:
logger->log("State: LOADDATA");
@@ -1600,6 +1604,8 @@ int main(int argc, char *argv[])
MonsterDB::load();
NPCDB::load();
EmoteDB::load();
+ StatusEffect::load();
+ Being::load(); // Hairstyles
// Load units
Units::loadUnits();
@@ -1610,10 +1616,13 @@ int main(int argc, char *argv[])
case STATE_LOGIN:
logger->log("State: LOGIN");
- if (!loginData.password.empty()) {
+ if (!loginData.password.empty())
+ {
loginData.registerLogin = false;
state = STATE_ACCOUNT;
- } else {
+ }
+ else
+ {
currentDialog = new LoginDialog(&loginData);
positionDialog(currentDialog, screenWidth,
screenHeight);
@@ -1639,8 +1648,7 @@ int main(int argc, char *argv[])
}
else
{
- int nextState = (options.skipUpdate) ?
- STATE_LOADDATA : STATE_UPDATE;
+ int nextState = STATE_UPDATE;
currentDialog = new ServerSelectDialog(&loginData,
nextState);
positionDialog(currentDialog, screenWidth,
@@ -1683,12 +1691,10 @@ int main(int argc, char *argv[])
delete progressBar;
delete progressLabel;
delete setup;
- delete setupWindow;
progressBar = NULL;
progressLabel = NULL;
currentDialog = NULL;
setup = NULL;
- setupWindow = NULL;
login_wallpaper->decRef();
login_wallpaper = NULL;
@@ -1700,18 +1706,21 @@ int main(int argc, char *argv[])
break;
case STATE_UPDATE:
- // Determine which source to use for the update host
- if (!options.updateHost.empty())
- updateHost = options.updateHost;
+ if (options.skipUpdate)
+ {
+ state = STATE_LOADDATA;
+ }
else
- updateHost = loginData.updateHost;
+ {
+ // Determine which source to use for the update host
+ if (!options.updateHost.empty())
+ updateHost = options.updateHost;
+ else
+ updateHost = loginData.updateHost;
- setUpdatesDir();
- logger->log("State: UPDATE");
+ setUpdatesDir();
+ logger->log("State: UPDATE");
- if (options.skipUpdate) {
- state = STATE_LOADDATA;
- } else {
currentDialog = new UpdaterWindow(updateHost,
homeDir + "/" + updatesDir);
positionDialog(currentDialog, screenWidth,
@@ -1763,12 +1772,12 @@ int main(int argc, char *argv[])
/*
* This loop can really stress the CPU, for no reason since it's
* just constantly redrawing the wallpaper. Added the following
- * usleep to limit it to 20 FPS during the login sequence
+ * usleep to limit it to 40 FPS during the login sequence
*/
- usleep(50000);
+ usleep(25000);
}
- delete textColor;
+ delete guiPalette;
#ifdef PACKAGE_VERSION
delete versionLabel;
#endif
@@ -1807,16 +1816,12 @@ void SetupListener::action(const gcn::ActionEvent &event)
Window *window = NULL;
if (event.getId() == "Setup")
- {
window = setupWindow;
- }
if (window)
{
window->setVisible(!window->isVisible());
if (window->isVisible())
- {
window->requestMoveToTop();
- }
}
}
diff --git a/src/map.cpp b/src/map.cpp
index e7646fd2..551c10f3 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -85,7 +85,7 @@ void TileAnimation::update()
Image *img = mAnimation->getCurrentImage();
if (img != mLastImage)
{
- for (std::list<std::pair<MapLayer*, int> >::iterator i =
+ for (std::list<std::pair<MapLayer*, int> >::iterator i =
mAffected.begin(); i != mAffected.end(); i++)
{
i->first->setTile(i->second, img);
@@ -119,10 +119,8 @@ Image* MapLayer::getTile(int x, int y) const
return mTiles[x + y * mWidth];
}
-void MapLayer::draw(Graphics *graphics,
- int startX, int startY,
- int endX, int endY,
- int scrollX, int scrollY,
+void MapLayer::draw(Graphics *graphics, int startX, int startY,
+ int endX, int endY, int scrollX, int scrollY,
const Sprites &sprites) const
{
startX -= mX;
@@ -167,8 +165,10 @@ void MapLayer::draw(Graphics *graphics,
}
// Draw any remaining sprites
- if (mIsFringeLayer) {
- while (si != sprites.end()) {
+ if (mIsFringeLayer)
+ {
+ while (si != sprites.end())
+ {
(*si)->draw(graphics, -scrollX, -scrollY);
si++;
}
diff --git a/src/monster.cpp b/src/monster.cpp
index deabd7a8..c8abcc05 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -27,13 +27,15 @@
#include "sound.h"
#include "text.h"
+#include "gui/palette.h"
+
#include "resources/monsterdb.h"
#include "resources/monsterinfo.h"
static const int NAME_X_OFFSET = 16;
static const int NAME_Y_OFFSET = 16;
-Monster::Monster(Uint32 id, Uint16 job, Map *map):
+Monster::Monster(int id, Uint16 job, Map *map):
Being(id, job, map),
mText(0)
{
@@ -71,7 +73,7 @@ Monster::Monster(Uint32 id, Uint16 job, Map *map):
}
}
- mNameColor = 0xff2020;
+ mNameColor = &guiPalette->getColor(Palette::MONSTER);
}
Monster::~Monster()
@@ -178,9 +180,9 @@ void Monster::handleAttack()
#else
-void Monster::handleAttack(Being *victim, int damage)
+void Monster::handleAttack(Being *victim, int damage, AttackType type)
{
- Being::handleAttack(victim, damage);
+ Being::handleAttack(victim, damage, type);
const MonsterInfo &mi = getInfo();
sound.playSfx(mi.getSound((damage > 0) ?
@@ -189,10 +191,10 @@ void Monster::handleAttack(Being *victim, int damage)
#endif
-void Monster::takeDamage(int amount)
+void Monster::takeDamage(Being *attacker, int amount, AttackType type)
{
if (amount > 0) sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT));
- Being::takeDamage(amount);
+ Being::takeDamage(attacker, amount, type);
}
Being::TargetCursorSize Monster::getTargetCursorSize() const
@@ -219,7 +221,8 @@ void Monster::showName(bool show)
{
mText = new Text(getInfo().getName(), mPx + NAME_X_OFFSET,
mPy + NAME_Y_OFFSET - getHeight(),
- gcn::Graphics::CENTER, gcn::Color(255, 64, 64));
+ gcn::Graphics::CENTER,
+ &guiPalette->getColor(Palette::MONSTER));
}
else
{
diff --git a/src/monster.h b/src/monster.h
index 5251d37e..34a2f237 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -30,7 +30,7 @@ class Text;
class Monster : public Being
{
public:
- Monster(Uint32 id, Uint16 job, Map *map);
+ Monster(int id, Uint16 job, Map *map);
~Monster();
@@ -49,21 +49,24 @@ class Monster : public Being
* Handles an attack of another being by this monster. Plays a hit or
* miss sound when appropriate.
*
- * @param victim The attacked being.
- * @param damage The amount of damage dealt (0 means miss).
+ * @param victim the victim being
+ * @param damage the amount of damage dealt (0 means miss)
+ * @param type the attack type
*/
#ifdef TMWSERV_SUPPORT
virtual void handleAttack();
#else
- virtual void handleAttack(Being *victim, int damage);
+ virtual void handleAttack(Being *victim, int damage, AttackType type);
#endif
/**
* Puts a damage bubble above this monster and plays the hurt sound
*
- * @param amount The amount of damage.
+ * @param attacker the attacking being
+ * @param damage the amount of damage recieved (0 means miss)
+ * @param type the attack type
*/
- virtual void takeDamage(int amount);
+ virtual void takeDamage(Being *attacker, int amount, AttackType type);
/**
* Returns the MonsterInfo, with static data about this monster.
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
index 1edc6079..3629b075 100644
--- a/src/net/ea/beinghandler.cpp
+++ b/src/net/ea/beinghandler.cpp
@@ -35,6 +35,10 @@
#include "../../npc.h"
#include "../../player_relations.h"
+#include "../../gui/npc_text.h"
+
+extern NpcTextDialog *npcTextDialog;
+
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
BeingHandler::BeingHandler(bool enableSync):
@@ -65,16 +69,16 @@ BeingHandler::BeingHandler(bool enableSync):
void BeingHandler::handleMessage(MessageIn &msg)
{
- Uint32 id;
+ int id;
Uint16 job, speed;
Uint16 headTop, headMid, headBottom;
Uint16 shoes, gloves;
Uint16 weapon, shield;
Uint16 gmstatus;
- Sint16 param1;
+ int param1;
int stunMode;
Uint32 statusEffects;
- Sint8 type;
+ int type;
Uint16 status;
Being *srcBeing, *dstBeing;
int hairStyle, hairColor, flag;
@@ -204,7 +208,12 @@ void BeingHandler::handleMessage(MessageIn &msg)
case SMSG_BEING_REMOVE:
// A being should be removed or has died
- dstBeing = beingManager->findBeing(msg.readInt32());
+ id = msg.readInt32();
+
+ if (id == current_npc)
+ npcTextDialog->showCloseButton();
+
+ dstBeing = beingManager->findBeing(id);
if (!dstBeing)
break;
@@ -213,9 +222,6 @@ void BeingHandler::handleMessage(MessageIn &msg)
if (dstBeing == player_node->getTarget())
player_node->stopAttack();
- if (dstBeing == current_npc)
- current_npc->handleDeath();
-
if (msg.readInt8() == 1)
dstBeing->setAction(Being::DEAD);
else
@@ -236,14 +242,17 @@ void BeingHandler::handleMessage(MessageIn &msg)
switch (type)
{
- case 0x0a: // Critical Damage
- if (dstBeing)
- dstBeing->showCrit();
- case 0x00: // Damage
+ case Being::HIT: // Damage
+ case Being::CRITICAL: // Critical Damage
+ case Being::MULTI: // Critical Damage
+ case Being::REFLECT: // Reflected Damage
+ case Being::FLEE: // Lucky Dodge
if (dstBeing)
- dstBeing->takeDamage(param1);
+ dstBeing->takeDamage(srcBeing, param1,
+ (Being::AttackType)type);
if (srcBeing)
- srcBeing->handleAttack(dstBeing, param1);
+ srcBeing->handleAttack(dstBeing, param1,
+ (Being::AttackType)type);
break;
case 0x02: // Sit
@@ -450,11 +459,6 @@ void BeingHandler::handleMessage(MessageIn &msg)
{
switch (msg.readInt8())
{
- case 1:
- if (dstBeing->getType() != Being::NPC)
- dstBeing->setAction(Being::DEAD);
- break;
-
case 2:
dstBeing->setAction(Being::SIT);
break;
diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp
index 480c71b8..8dbc2953 100644
--- a/src/net/ea/buysellhandler.cpp
+++ b/src/net/ea/buysellhandler.cpp
@@ -32,15 +32,12 @@
#include "../../npc.h"
#include "../../gui/buy.h"
+#include "../../gui/buysell.h"
#include "../../gui/chat.h"
#include "../../gui/sell.h"
#include "../../utils/gettext.h"
-extern BuyDialog *buyDialog;
-extern Window *buySellDialog;
-extern SellDialog *sellDialog;
-
BuySellHandler::BuySellHandler()
{
static const Uint16 _messages[] = {
@@ -64,8 +61,8 @@ void BuySellHandler::handleMessage(MessageIn &msg)
buyDialog->reset();
sellDialog->setVisible(false);
sellDialog->reset();
+ current_npc = msg.readInt32();
buySellDialog->setVisible(true);
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg.readInt32()));
break;
case SMSG_NPC_BUY:
@@ -77,10 +74,10 @@ void BuySellHandler::handleMessage(MessageIn &msg)
for (int k = 0; k < n_items; k++)
{
- Sint32 value = msg.readInt32();
+ int value = msg.readInt32();
msg.readInt32(); // DCvalue
msg.readInt8(); // type
- Sint16 itemId = msg.readInt16();
+ int itemId = msg.readInt16();
buyDialog->addItem(itemId, 0, value);
}
break;
@@ -88,33 +85,38 @@ void BuySellHandler::handleMessage(MessageIn &msg)
case SMSG_NPC_SELL:
msg.readInt16(); // length
n_items = (msg.getLength() - 4) / 10;
- if (n_items > 0) {
+ if (n_items > 0)
+ {
sellDialog->setMoney(player_node->getMoney());
sellDialog->reset();
sellDialog->setVisible(true);
for (int k = 0; k < n_items; k++)
{
- Sint16 index = msg.readInt16();
- Sint32 value = msg.readInt32();
+ int index = msg.readInt16();
+ int value = msg.readInt32();
msg.readInt32(); // OCvalue
Item *item = player_node->getInventory()->getItem(index);
- if (item && !(item->isEquipped())) {
+
+ if (item && !(item->isEquipped()))
sellDialog->addItem(item, value);
- }
}
}
- else {
+ else
+ {
chatWindow->chatLog(_("Nothing to sell"), BY_SERVER);
- if (current_npc) current_npc->handleDeath();
+ current_npc = 0;
}
break;
case SMSG_NPC_BUY_RESPONSE:
- if (msg.readInt8() == 0) {
+ if (msg.readInt8() == 0)
+ {
chatWindow->chatLog(_("Thanks for buying"), BY_SERVER);
- } else {
+ }
+ else
+ {
// Reset player money since buy dialog already assumed purchase
// would go fine
buyDialog->setMoney(player_node->getMoney());
@@ -123,11 +125,11 @@ void BuySellHandler::handleMessage(MessageIn &msg)
break;
case SMSG_NPC_SELL_RESPONSE:
- if (msg.readInt8() == 0) {
+ if (msg.readInt8() == 0)
chatWindow->chatLog(_("Thanks for selling"), BY_SERVER);
- } else {
+ else
chatWindow->chatLog(_("Unable to sell"), BY_SERVER);
- }
+
break;
}
}
diff --git a/src/net/ea/chathandler.cpp b/src/net/ea/chathandler.cpp
index 0293f987..4842c86f 100644
--- a/src/net/ea/chathandler.cpp
+++ b/src/net/ea/chathandler.cpp
@@ -60,7 +60,7 @@ void ChatHandler::handleMessage(MessageIn &msg)
Being *being;
std::string chatMsg;
std::string nick;
- Sint16 chatMsgLength;
+ int chatMsgLength;
switch (msg.getId())
{
diff --git a/src/net/ea/equipmenthandler.cpp b/src/net/ea/equipmenthandler.cpp
index 19063daf..f5377cf2 100644
--- a/src/net/ea/equipmenthandler.cpp
+++ b/src/net/ea/equipmenthandler.cpp
@@ -48,9 +48,9 @@ EquipmentHandler::EquipmentHandler()
void EquipmentHandler::handleMessage(MessageIn &msg)
{
- Sint32 itemCount;
- Sint16 index, equipPoint, itemId;
- Sint8 type;
+ int itemCount;
+ int index, equipPoint, itemId;
+ int type;
int mask, position;
Item *item;
Inventory *inventory = player_node->getInventory();
diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp
index 71eee291..addcb06f 100644
--- a/src/net/ea/inventoryhandler.cpp
+++ b/src/net/ea/inventoryhandler.cpp
@@ -25,6 +25,7 @@
#include "../messagein.h"
#include "protocol.h"
+#include "../../configuration.h"
#include "../../inventory.h"
#include "../../item.h"
#include "../../itemshortcut.h"
@@ -32,6 +33,7 @@
#include "../../log.h"
#include "../../gui/chat.h"
+#include "../../gui/storagewindow.h"
#include "../../resources/iteminfo.h"
@@ -60,9 +62,9 @@ InventoryHandler::InventoryHandler()
void InventoryHandler::handleMessage(MessageIn &msg)
{
- Sint32 number;
- Sint16 index, amount, itemId, equipType, arrow;
- Sint16 identified, cards[4], itemType;
+ int number;
+ int index, amount, itemId, equipType, arrow;
+ int identified, cards[4], itemType;
Inventory *inventory = player_node->getInventory();
Inventory *storage = player_node->getStorage();
@@ -70,7 +72,6 @@ void InventoryHandler::handleMessage(MessageIn &msg)
{
case SMSG_PLAYER_INVENTORY:
case SMSG_PLAYER_STORAGE_ITEMS:
- case SMSG_PLAYER_STORAGE_EQUIP:
switch (msg.getId()) {
case SMSG_PLAYER_INVENTORY:
// Clear inventory - this will be a complete refresh
@@ -84,11 +85,10 @@ void InventoryHandler::handleMessage(MessageIn &msg)
* clear storage here
*/
storage->clear();
- logger->log("Received SMSG_PLAYER_STORAGE_ITEMS");
break;
default:
- logger->log("Received SMSG_PLAYER_STORAGE_EQUIP");
- break;
+ logger->log("HOW DID WE GET HERE?");
+ return;
}
msg.readInt16(); // length
number = (msg.getLength() - 4) / 18;
@@ -98,17 +98,8 @@ void InventoryHandler::handleMessage(MessageIn &msg)
itemId = msg.readInt16();
itemType = msg.readInt8();
identified = msg.readInt8();
- if (msg.getId() == SMSG_PLAYER_STORAGE_EQUIP) {
- amount = 1;
- msg.readInt16(); // Equip Point?
- } else {
- amount = msg.readInt16();
- }
+ amount = msg.readInt16();
arrow = msg.readInt16();
- if (msg.getId() == SMSG_PLAYER_STORAGE_EQUIP) {
- msg.readInt8(); // Attribute (broken)
- msg.readInt8(); // Refine level
- }
for (int i = 0; i < 4; i++)
cards[i] = msg.readInt16();
@@ -128,6 +119,29 @@ void InventoryHandler::handleMessage(MessageIn &msg)
}
break;
+ case SMSG_PLAYER_STORAGE_EQUIP:
+ msg.readInt16(); // length
+ number = (msg.getLength() - 4) / 20;
+
+ for (int loop = 0; loop < number; loop++) {
+ index = msg.readInt16();
+ itemId = msg.readInt16();
+ itemType = msg.readInt8();
+ identified = msg.readInt8();
+ amount = 1;
+ msg.readInt16(); // Equip Point?
+ msg.readInt16(); // Another Equip Point?
+ msg.readInt8(); // Attribute (broken)
+ msg.readInt8(); // Refine level
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg.readInt16();
+
+ logger->log("Index:%d, ID:%d, Type:%d, Identified:%d, Qty:%d, Cards:%d, %d, %d, %d",
+ index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]);
+ storage->setItem(index, itemId, amount, false);
+ }
+ break;
+
case SMSG_PLAYER_INVENTORY_ADD:
index = msg.readInt16();
amount = msg.readInt16();
@@ -141,13 +155,21 @@ void InventoryHandler::handleMessage(MessageIn &msg)
itemType = msg.readInt8();
if (msg.readInt8() > 0) {
- chatWindow->chatLog(_("Unable to pick up item"), BY_SERVER);
+ if (config.getValue("showpickupchat", true)) {
+ chatWindow->chatLog(_("Unable to pick up item"), BY_SERVER);
+ }
} else {
const ItemInfo &itemInfo = ItemDB::get(itemId);
const std::string amountStr =
(amount > 1) ? toString(amount) : "a";
- chatWindow->chatLog(strprintf(_("You picked up %s %s"),
- amountStr.c_str(), itemInfo.getName().c_str()), BY_SERVER);
+ if (config.getValue("showpickupchat", true)) {
+ chatWindow->chatLog(strprintf(_("You picked up %s [%s]"),
+ amountStr.c_str(), itemInfo.getName().c_str()),
+ BY_SERVER);
+ }
+ if (config.getValue("showpickupparticle", false)) {
+ player_node->pickedUp(itemInfo.getName());
+ }
if (Item *item = inventory->getItem(index)) {
item->setId(itemId);
@@ -193,35 +215,54 @@ void InventoryHandler::handleMessage(MessageIn &msg)
case SMSG_PLAYER_STORAGE_STATUS:
/*
- * Basic slots used vs total slots info
- * We don't really need this information, but this is
- * the closest we get to an "Open Storage" packet
- * from the server. It always comes after the two
- * SMSG_PLAYER_STORAGE_... packets that update
- * storage contents.
+ * This is the closest we get to an "Open Storage" packet from the
+ * server. It always comes after the two SMSG_PLAYER_STORAGE_...
+ * packets that update storage contents.
*/
- logger->log("Received SMSG_PLAYER_STORAGE_STATUS");
player_node->setInStorage(true);
+ msg.readInt16(); // Storage capacity
+ msg.readInt16(); // Used count
break;
case SMSG_PLAYER_STORAGE_ADD:
/*
* Move an item into storage
*/
+ index = msg.readInt16();
+ amount = msg.readInt32();
+ itemId = msg.readInt16();
+ identified = msg.readInt8();
+ msg.readInt8(); // attribute
+ msg.readInt8(); // refine
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg.readInt16();
+
+ if (Item *item = storage->getItem(index)) {
+ item->setId(itemId);
+ item->increaseQuantity(amount);
+ } else {
+ storage->setItem(index, itemId, amount, false);
+ }
break;
case SMSG_PLAYER_STORAGE_REMOVE:
/*
- * Move an item out of storage
- */
+ * Move an item out of storage
+ */
+ index = msg.readInt16();
+ amount = msg.readInt16();
+ if (Item *item = storage->getItem(index)) {
+ item->increaseQuantity(-amount);
+ if (item->getQuantity() == 0)
+ storage->removeItemAt(index);
+ }
break;
case SMSG_PLAYER_STORAGE_CLOSE:
/*
- * Storage access has been closed
- */
+ * Storage access has been closed
+ */
player_node->setInStorage(false);
- logger->log("Received SMSG_PLAYER_STORAGE_CLOSE");
break;
}
}
diff --git a/src/net/ea/npchandler.cpp b/src/net/ea/npchandler.cpp
index 068a3be6..7bd23135 100644
--- a/src/net/ea/npchandler.cpp
+++ b/src/net/ea/npchandler.cpp
@@ -19,6 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <SDL_types.h>
+
#include "../messagein.h"
#include "npchandler.h"
#include "protocol.h"
@@ -32,11 +34,6 @@
#include "../../gui/npclistdialog.h"
#include "../../gui/npcstringdialog.h"
-extern NpcIntegerDialog *npcIntegerDialog;
-extern NpcListDialog *npcListDialog;
-extern NpcTextDialog *npcTextDialog;
-extern NpcStringDialog *npcStringDialog;
-
NPCHandler::NPCHandler()
{
static const Uint16 _messages[] = {
@@ -59,40 +56,44 @@ void NPCHandler::handleMessage(MessageIn &msg)
{
case SMSG_NPC_CHOICE:
msg.readInt16(); // length
- id = msg.readInt32();
+ current_npc = msg.readInt32();
player_node->setAction(LocalPlayer::STAND);
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcListDialog->parseItems(msg.readString(msg.getLength() - 8));
- npcListDialog->setVisible(true);
+ npcListDialog->requestFocus();
break;
case SMSG_NPC_MESSAGE:
msg.readInt16(); // length
- id = msg.readInt32();
+ current_npc = msg.readInt32();
player_node->setAction(LocalPlayer::STAND);
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcTextDialog->addText(msg.readString(msg.getLength() - 8));
- npcListDialog->setVisible(false);
- npcTextDialog->setVisible(true);
+ npcTextDialog->requestFocus();
break;
case SMSG_NPC_CLOSE:
id = msg.readInt32();
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
- npcTextDialog->showCloseButton();
+ // If we're talking to that NPC, show the close button
+ if (id == current_npc)
+ npcTextDialog->showCloseButton();
+ // Otherwise, move on as an empty dialog doesn't help
+ else
+ npcTextDialog->closeDialog(id);
break;
case SMSG_NPC_NEXT:
- // Next button in NPC dialog, currently unused
id = msg.readInt32();
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
- npcTextDialog->showNextButton();
+ // If we're talking to that NPC, show the next button
+ if (id == current_npc)
+ npcTextDialog->showNextButton();
+ // Otherwise, move on as an empty dialog doesn't help
+ else
+ npcTextDialog->nextDialog(id);
break;
case SMSG_NPC_INT_INPUT:
// Request for an integer
- id = msg.readInt32();
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
+ current_npc = msg.readInt32();
+ player_node->setAction(LocalPlayer::STAND);
npcIntegerDialog->setRange(0, 2147483647);
npcIntegerDialog->setDefaultValue(0);
npcIntegerDialog->setVisible(true);
@@ -101,8 +102,8 @@ void NPCHandler::handleMessage(MessageIn &msg)
case SMSG_NPC_STR_INPUT:
// Request for a string
- id = msg.readInt32();
- current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
+ current_npc = msg.readInt32();
+ player_node->setAction(LocalPlayer::STAND);
npcStringDialog->setValue("");
npcStringDialog->setVisible(true);
npcStringDialog->requestFocus();
diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp
index 9f0acbb3..fcc44cb0 100644
--- a/src/net/ea/playerhandler.cpp
+++ b/src/net/ea/playerhandler.cpp
@@ -30,13 +30,17 @@
#include "../../units.h"
#include "../../gui/buy.h"
+#include "../../gui/buysell.h"
#include "../../gui/chat.h"
#include "../../gui/gui.h"
-#include "../../gui/npclistdialog.h"
#include "../../gui/npc_text.h"
+#include "../../gui/npcintegerdialog.h"
+#include "../../gui/npclistdialog.h"
+#include "../../gui/npcstringdialog.h"
#include "../../gui/ok_dialog.h"
#include "../../gui/sell.h"
#include "../../gui/skill.h"
+#include "../../gui/storagewindow.h"
#include "../../gui/viewport.h"
#include "../../utils/stringutils.h"
@@ -46,12 +50,6 @@
OkDialog *weightNotice = NULL;
OkDialog *deathNotice = NULL;
-extern NpcListDialog *npcListDialog;
-extern NpcTextDialog *npcTextDialog;
-extern BuyDialog *buyDialog;
-extern SellDialog *sellDialog;
-extern Window *buySellDialog;
-
// Max. distance we are willing to scroll after a teleport;
// everything beyond will reset the port hard.
static const int MAP_TELEPORT_SCROLL_DISTANCE = 8;
@@ -81,12 +79,19 @@ namespace {
{
player_node->revive();
deathNotice = NULL;
+ npcIntegerDialog->reset();
+ npcIntegerDialog->setVisible(false);
+ npcListDialog->reset();
npcListDialog->setVisible(false);
+ npcStringDialog->setValue("");
+ npcStringDialog->setVisible(false);
+ npcTextDialog->clearText();
npcTextDialog->setVisible(false);
buyDialog->setVisible(false);
sellDialog->setVisible(false);
buySellDialog->setVisible(false);
- if (current_npc) current_npc->handleDeath();
+
+ if (storageWindow->isVisible()) storageWindow->close();
}
} deathListener;
}
@@ -140,8 +145,6 @@ void PlayerHandler::handleMessage(MessageIn &msg)
// Switch the actual map, deleting the previous one if necessary
engine->changeMap(mapPath);
- if (current_npc) current_npc->handleDeath();
-
float scrollOffsetX = 0.0f;
float scrollOffsetY = 0.0f;
@@ -160,8 +163,8 @@ void PlayerHandler::handleMessage(MessageIn &msg)
player_node->mY = y;
logger->log("Adjust scrolling by %d:%d",
- (int)scrollOffsetX,
- (int)scrollOffsetY);
+ (int) scrollOffsetX,
+ (int) scrollOffsetY);
viewport->scrollBy(scrollOffsetX, scrollOffsetY);
}
@@ -169,7 +172,7 @@ void PlayerHandler::handleMessage(MessageIn &msg)
case SMSG_PLAYER_STAT_UPDATE_1:
{
- Sint16 type = msg.readInt16();
+ int type = msg.readInt16();
Uint32 value = msg.readInt32();
switch (type)
@@ -297,10 +300,10 @@ void PlayerHandler::handleMessage(MessageIn &msg)
case SMSG_PLAYER_STAT_UPDATE_3:
{
- Sint32 type = msg.readInt32();
- Sint32 base = msg.readInt32();
- Sint32 bonus = msg.readInt32();
- Sint32 total = base + bonus;
+ int type = msg.readInt32();
+ int base = msg.readInt32();
+ int bonus = msg.readInt32();
+ int total = base + bonus;
switch (type) {
case 0x000d: player_node->mAttr[LocalPlayer::STR] = total;
@@ -321,9 +324,9 @@ void PlayerHandler::handleMessage(MessageIn &msg)
case SMSG_PLAYER_STAT_UPDATE_4:
{
- Sint16 type = msg.readInt16();
- Sint8 fail = msg.readInt8();
- Sint8 value = msg.readInt8();
+ int type = msg.readInt16();
+ int fail = msg.readInt8();
+ int value = msg.readInt8();
if (fail != 1)
break;
@@ -400,7 +403,7 @@ void PlayerHandler::handleMessage(MessageIn &msg)
case SMSG_PLAYER_ARROW_MESSAGE:
{
- Sint16 type = msg.readInt16();
+ int type = msg.readInt16();
switch (type) {
case 0:
diff --git a/src/net/ea/protocol.h b/src/net/ea/protocol.h
index 55c0d8b6..b806b13b 100644
--- a/src/net/ea/protocol.h
+++ b/src/net/ea/protocol.h
@@ -121,30 +121,32 @@
#define CMSG_TRADE_RESPONSE 0x00e6
#define CMSG_ITEM_PICKUP 0x009f
#define CMSG_MAP_LOADED 0x007d
-#define CMSG_NPC_BUY_REQUEST 0x00c8
-#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5
#define CMSG_CHAT_MESSAGE 0x008c
#define CMSG_CHAT_WHISPER 0x0096
#define CMSG_CHAT_ANNOUNCE 0x0099
#define CMSG_CHAT_WHO 0x00c1
-#define CMSG_NPC_LIST_CHOICE 0x00b8
-#define CMSG_NPC_NEXT_REQUEST 0x00b9
-#define CMSG_NPC_SELL_REQUEST 0x00c9
-#define CMSG_NPC_INT_RESPONSE 0x0143
-#define CMSG_NPC_STR_RESPONSE 0x01d5
#define CMSG_SKILL_LEVELUP_REQUEST 0x0112
#define CMSG_STAT_UPDATE_REQUEST 0x00bb
#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8
#define CMSG_TRADE_CANCEL_REQUEST 0x00ed
#define CMSG_TRADE_ADD_COMPLETE 0x00eb
#define CMSG_TRADE_OK 0x00ef
-#define CMSG_NPC_TALK 0x0090
#define CMSG_TRADE_REQUEST 0x00e4
#define CMSG_PLAYER_INVENTORY_USE 0x00a7
#define CMSG_PLAYER_INVENTORY_DROP 0x00a2
#define CMSG_PLAYER_EQUIP 0x00a9
#define CMSG_PLAYER_UNEQUIP 0x00ab
+#define CMSG_NPC_TALK 0x0090
+#define CMSG_NPC_NEXT_REQUEST 0x00b9
+#define CMSG_NPC_CLOSE 0x0146
+#define CMSG_NPC_LIST_CHOICE 0x00b8
+#define CMSG_NPC_INT_RESPONSE 0x0143
+#define CMSG_NPC_STR_RESPONSE 0x01d5
+#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5
+#define CMSG_NPC_BUY_REQUEST 0x00c8
+#define CMSG_NPC_SELL_REQUEST 0x00c9
+
#define CMSG_PARTY_CREATE 0x00f9
#define CMSG_PARTY_INVITE 0x00fc
#define CMSG_PARTY_INVITED 0x00ff
diff --git a/src/net/ea/skillhandler.cpp b/src/net/ea/skillhandler.cpp
index 4361b147..12c38aaa 100644
--- a/src/net/ea/skillhandler.cpp
+++ b/src/net/ea/skillhandler.cpp
@@ -85,14 +85,14 @@ void SkillHandler::handleMessage(MessageIn &msg)
for (int k = 0; k < skillCount; k++)
{
- Sint16 skillId = msg.readInt16();
+ int skillId = msg.readInt16();
msg.readInt16(); // target type
msg.readInt16(); // unknown
- Sint16 level = msg.readInt16();
- Sint16 sp = msg.readInt16();
+ int level = msg.readInt16();
+ int sp = msg.readInt16();
msg.readInt16(); // range
std::string skillName = msg.readString(24);
- Sint8 up = msg.readInt8();
+ int up = msg.readInt8();
if (level != 0 || up != 0)
{
diff --git a/src/net/ea/tradehandler.cpp b/src/net/ea/tradehandler.cpp
index 6c953a11..78472083 100644
--- a/src/net/ea/tradehandler.cpp
+++ b/src/net/ea/tradehandler.cpp
@@ -140,8 +140,8 @@ void TradeHandler::handleMessage(MessageIn &msg)
case SMSG_TRADE_ITEM_ADD:
{
- Sint32 amount = msg.readInt32();
- Sint16 type = msg.readInt16();
+ int amount = msg.readInt32();
+ int type = msg.readInt16();
msg.readInt8(); // identified flag
msg.readInt8(); // attribute
msg.readInt8(); // refine
@@ -166,7 +166,7 @@ void TradeHandler::handleMessage(MessageIn &msg)
tradeWindow->receivedOk(true);
return;
}
- Sint16 quantity = msg.readInt16();
+ int quantity = msg.readInt16();
switch (msg.readInt8())
{
diff --git a/src/net/tmwserv/beinghandler.cpp b/src/net/tmwserv/beinghandler.cpp
index ac33b6fe..947d6b80 100644
--- a/src/net/tmwserv/beinghandler.cpp
+++ b/src/net/tmwserv/beinghandler.cpp
@@ -289,7 +289,7 @@ void BeingHandler::handleBeingsDamageMessage(MessageIn &msg)
int damage = msg.readInt16();
if (being)
{
- being->takeDamage(damage);
+ being->takeDamage(0, damage, Being::HIT);
}
}
}
diff --git a/src/net/tmwserv/buysellhandler.cpp b/src/net/tmwserv/buysellhandler.cpp
index 54750cbb..6e4b9d56 100644
--- a/src/net/tmwserv/buysellhandler.cpp
+++ b/src/net/tmwserv/buysellhandler.cpp
@@ -57,7 +57,7 @@ void BuySellHandler::handleMessage(MessageIn &msg)
return;
}
- current_npc = static_cast< NPC * >(being);
+ current_npc = being->getId();
switch (msg.getId())
{
diff --git a/src/net/tmwserv/npchandler.cpp b/src/net/tmwserv/npchandler.cpp
index 53f3c7b2..b3e36749 100644
--- a/src/net/tmwserv/npchandler.cpp
+++ b/src/net/tmwserv/npchandler.cpp
@@ -55,7 +55,7 @@ void NPCHandler::handleMessage(MessageIn &msg)
return;
}
- current_npc = static_cast< NPC * >(being);
+ current_npc = being->getId();
switch (msg.getId())
{
diff --git a/src/net/tmwserv/playerhandler.cpp b/src/net/tmwserv/playerhandler.cpp
index d4850f43..f4cc4b23 100644
--- a/src/net/tmwserv/playerhandler.cpp
+++ b/src/net/tmwserv/playerhandler.cpp
@@ -84,7 +84,9 @@ namespace {
npcTextDialog->setVisible(false);
buyDialog->setVisible(false);
sellDialog->setVisible(false);
+#ifdef EATHENA_SUPPORT
buySellDialog->setVisible(false);
+#endif
current_npc = 0;
}
} deathListener;
diff --git a/src/npc.cpp b/src/npc.cpp
index 792d1aa4..df43d548 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -20,11 +20,13 @@
*/
#include "animatedsprite.h"
+#include "beingmanager.h"
#include "npc.h"
#include "particle.h"
#include "text.h"
#include "gui/npc_text.h"
+#include "gui/palette.h"
#ifdef TMWSERV_SUPPORT
#include "net/tmwserv/gameserver/player.h"
@@ -35,9 +37,8 @@
#include "resources/npcdb.h"
-extern NpcTextDialog *npcTextDialog;
-
-NPC *current_npc = 0;
+bool NPC::isTalking = false;
+int current_npc = 0;
static const int NAME_X_OFFSET = 15;
static const int NAME_Y_OFFSET = 30;
@@ -46,7 +47,7 @@ static const int NAME_Y_OFFSET = 30;
NPC::NPC(Uint16 id, int job, Map *map):
Player(id, job, map)
#else
-NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network):
+NPC::NPC(int id, Uint16 job, Map *map, Network *network):
Player(id, job, map),
mNetwork(network)
#endif
@@ -59,7 +60,8 @@ NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network):
i != info.sprites.end();
i++)
{
- if (c == VECTOREND_SPRITE) break;
+ if (c == VECTOREND_SPRITE)
+ break;
std::string file = "graphics/sprites/" + (*i)->sprite;
int variant = (*i)->variant;
@@ -80,14 +82,12 @@ NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network):
}
mName = 0;
- mNameColor = 0x21bbbb;
+ mNameColor = &guiPalette->getColor(Palette::NPC);
}
NPC::~NPC()
{
delete mName;
-
- if (current_npc == this) handleDeath();
}
void NPC::setName(const std::string &name)
@@ -96,7 +96,8 @@ void NPC::setName(const std::string &name)
delete mName;
mName = new Text(displayName, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
- gcn::Graphics::CENTER, gcn::Color(200, 200, 255));
+ gcn::Graphics::CENTER,
+ &guiPalette->getColor(Palette::NPC));
Being::setName(displayName + " (NPC)");
}
@@ -118,88 +119,25 @@ Being::Type NPC::getType() const
void NPC::talk()
{
-#ifdef TMWSERV_SUPPORT
- Net::GameServer::Player::talkToNPC(mId, true);
-#else
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_TALK);
- outMsg.writeInt32(mId);
- outMsg.writeInt8(0);
-#endif
- current_npc = this;
-}
+ if (isTalking)
+ return;
-void NPC::nextDialog()
-{
-#ifdef TMWSERV_SUPPORT
- Net::GameServer::Player::talkToNPC(mId, false);
-#else
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST);
- outMsg.writeInt32(mId);
-#endif
-}
+ isTalking = true;
-void NPC::dialogChoice(char choice)
-{
#ifdef TMWSERV_SUPPORT
- Net::GameServer::Player::selectFromNPC(mId, choice);
+ Net::GameServer::Player::talkToNPC(mId, true);
#else
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_LIST_CHOICE);
- outMsg.writeInt32(mId);
- outMsg.writeInt8(choice);
-#endif
-}
-
-void NPC::integerInput(int value)
-{
-#ifdef EATHENA_SUPPORT
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_INT_RESPONSE);
- outMsg.writeInt32(mId);
- outMsg.writeInt32(value);
-#endif
-}
+ if (!mNetwork)
+ return;
-void NPC::stringInput(const std::string &value)
-{
-#ifdef EATHENA_SUPPORT
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_STR_RESPONSE);
- outMsg.writeInt16(value.length() + 9);
- outMsg.writeInt32(mId);
- outMsg.writeString(value, value.length());
- outMsg.writeInt8(0);
-#endif
-}
-
-/*
- * TODO Unify the buy() and sell() methods, without sacrificing readability of
- * the code calling the method. buy(bool buySell) would be bad...
- */
-void NPC::buy()
-{
- // XXX Convert for new server
-#ifdef EATHENA_SUPPORT
MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST);
+ outMsg.writeInt16(CMSG_NPC_TALK);
+ outMsg.writeInt16(CMSG_NPC_TALK);
outMsg.writeInt32(mId);
outMsg.writeInt8(0);
#endif
}
-void NPC::sell()
-{
- // XXX Convert for new server
-#ifdef EATHENA_SUPPORT
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST);
- outMsg.writeInt32(mId);
- outMsg.writeInt8(1);
-#endif
-}
-
void NPC::updateCoords()
{
if (mName)
@@ -215,13 +153,3 @@ void NPC::updateCoords()
mName->adviseXY(px, py);
}
}
-
-void NPC::handleDeath()
-{
- printf("NPC::handleDeath\n");
- if (this != current_npc) return;
-
- if (npcTextDialog->isVisible())
- npcTextDialog->showCloseButton();
- else current_npc = NULL;
-}
diff --git a/src/npc.h b/src/npc.h
index b003b82e..fed03b51 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -36,7 +36,7 @@ class NPC : public Player
#ifdef TMWSERV_SUPPORT
NPC(Uint16 id, int sprite, Map *map);
#else
- NPC(Uint32 id, Uint16 job, Map *map, Network *network);
+ NPC(int id, Uint16 job, Map *map, Network *network);
#endif
~NPC();
@@ -48,19 +48,6 @@ class NPC : public Player
virtual Type getType() const;
void talk();
- void nextDialog();
- void dialogChoice(char choice);
- void integerInput(int value);
- void stringInput(const std::string &value);
-
- void buy();
- void sell();
-
- /**
- * Call this to ease clean up of the current NPC, without causing
- * interface problems
- */
- void handleDeath();
/**
* Gets the way an NPC is blocked by other things on the map
@@ -68,6 +55,7 @@ class NPC : public Player
virtual unsigned char getWalkMask() const
{ return 0x83; } // blocked like a monster by walls, monsters and characters ( bin 1000 0011)
+ static bool isTalking;
protected:
/**
* Gets the way a monster blocks pathfinding for other objects
@@ -83,6 +71,6 @@ class NPC : public Player
Text *mName;
};
-extern NPC *current_npc;
+extern int current_npc;
#endif
diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp
index e7e7b204..7a1d259e 100644
--- a/src/openglgraphics.cpp
+++ b/src/openglgraphics.cpp
@@ -26,12 +26,12 @@
#include "resources/image.h"
+#ifdef USE_OPENGL
+
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
-#ifdef USE_OPENGL
-
#ifndef GL_TEXTURE_RECTANGLE_ARB
#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
@@ -62,18 +62,17 @@ bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
mFullscreen = fs;
mHWAccel = hwaccel;
- if (fs) {
+ if (fs)
displayFlags |= SDL_FULLSCREEN;
- }
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- if (!(mScreen = SDL_SetVideoMode(w, h, bpp, displayFlags))) {
+ if (!(mScreen = SDL_SetVideoMode(w, h, bpp, displayFlags)))
return false;
- }
#ifdef __APPLE__
- if (mSync) {
+ if (mSync)
+ {
const GLint VBL = 1;
CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
}
@@ -110,6 +109,8 @@ bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
bool OpenGLGraphics::drawImage(Image *image, int srcX, int srcY,
int dstX, int dstY, int width, int height, bool useColor)
{
+ if (!image) return false;
+
srcX += image->mBounds.x;
srcY += image->mBounds.y;
@@ -157,13 +158,80 @@ bool OpenGLGraphics::drawImage(Image *image, int srcX, int srcY,
glEnd();
if (!useColor)
- {
glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
- }
return true;
}
+/* Optimising the functions that Graphics::drawImagePattern would call,
+ * so that glBegin...glEnd are outside the main loop. */
+void OpenGLGraphics::drawImagePattern(Image *image, int x, int y, int w, int h)
+{
+ if (!image) return;
+
+ const int srcX = image->mBounds.x;
+ const int srcY = image->mBounds.y;
+
+ const float texX1 = srcX / (float)image->mTexWidth;
+ const float texY1 = srcY / (float)image->mTexHeight;
+
+ int iw = image->getWidth();
+ int ih = image->getHeight();
+ if (iw == 0 || ih == 0)
+ return;
+
+ glColor4f(1.0f, 1.0f, 1.0f, image->mAlpha);
+
+ glBindTexture(Image::mTextureType, image->mGLImage);
+
+ setTexturingAndBlending(true);
+
+ // Draw a set of textured rectangles
+ glBegin(GL_QUADS);
+
+ for (int py = 0; py < h; py += ih)
+ {
+ int height = (py + ih >= h) ? h - py : ih;
+ int dstY = y + py;
+ for (int px = 0; px < w; px += iw)
+ {
+ int width = (px + iw >= w) ? w - px : iw;
+ int dstX = x + px;
+
+ if (Image::mTextureType == GL_TEXTURE_2D)
+ {
+ // Find OpenGL normalized texture coordinates.
+ float texX2 = (srcX + width) / (float) image->mTexWidth;
+ float texY2 = (srcY + height) / (float) image->mTexHeight;
+
+ glTexCoord2f(texX1, texY1);
+ glVertex2i(dstX, dstY);
+ glTexCoord2f(texX2, texY1);
+ glVertex2i(dstX + width, dstY);
+ glTexCoord2f(texX2, texY2);
+ glVertex2i(dstX + width, dstY + height);
+ glTexCoord2f(texX1, texY2);
+ glVertex2i(dstX, dstY + height);
+ }
+ else
+ {
+ glTexCoord2i(srcX, srcY);
+ glVertex2i(dstX, dstY);
+ glTexCoord2i(srcX + width, srcY);
+ glVertex2i(dstX + width, dstY);
+ glTexCoord2i(srcX + width, srcY + height);
+ glVertex2i(dstX + width, dstY + height);
+ glTexCoord2i(srcX, srcY + height);
+ glVertex2i(dstX, dstY + height);
+ }
+ }
+ }
+
+ glEnd();
+
+ glColor4ub(mColor.r, mColor.g, mColor.b, mColor.a);
+}
+
void OpenGLGraphics::updateScreen()
{
glFlush();
@@ -205,9 +273,8 @@ SDL_Surface* OpenGLGraphics::getScreenshot()
w, h, 24,
0xff0000, 0x00ff00, 0x0000ff, 0x000000);
- if (SDL_MUSTLOCK(screenshot)) {
+ if (SDL_MUSTLOCK(screenshot))
SDL_LockSurface(screenshot);
- }
// Grap the pixel buffer and write it to the SDL surface
glPixelStorei(GL_PACK_ALIGNMENT, 1);
@@ -229,9 +296,8 @@ SDL_Surface* OpenGLGraphics::getScreenshot()
free(buf);
- if (SDL_MUSTLOCK(screenshot)) {
+ if (SDL_MUSTLOCK(screenshot))
SDL_UnlockSurface(screenshot);
- }
return screenshot;
}
@@ -241,7 +307,8 @@ bool OpenGLGraphics::pushClipArea(gcn::Rectangle area)
int transX = 0;
int transY = 0;
- if (!mClipStack.empty()) {
+ if (!mClipStack.empty())
+ {
transX = -mClipStack.top().xOffset;
transY = -mClipStack.top().yOffset;
}
@@ -266,9 +333,7 @@ void OpenGLGraphics::popClipArea()
gcn::Graphics::popClipArea();
if (mClipStack.empty())
- {
return;
- }
glPopMatrix();
glScissor(mClipStack.top().x,
@@ -324,8 +389,10 @@ void OpenGLGraphics::setTargetPlane(int width, int height)
void OpenGLGraphics::setTexturingAndBlending(bool enable)
{
- if (enable) {
- if (!mTexture) {
+ if (enable)
+ {
+ if (!mTexture)
+ {
glEnable(Image::mTextureType);
mTexture = true;
}
@@ -335,16 +402,22 @@ void OpenGLGraphics::setTexturingAndBlending(bool enable)
glEnable(GL_BLEND);
mAlpha = true;
}
- } else {
- if (mAlpha && !mColorAlpha) {
+ }
+ else
+ {
+ if (mAlpha && !mColorAlpha)
+ {
glDisable(GL_BLEND);
mAlpha = false;
- } else if (!mAlpha && mColorAlpha) {
+ }
+ else if (!mAlpha && mColorAlpha)
+ {
glEnable(GL_BLEND);
mAlpha = true;
}
- if (mTexture) {
+ if (mTexture)
+ {
glDisable(Image::mTextureType);
mTexture = false;
}
diff --git a/src/openglgraphics.h b/src/openglgraphics.h
index 566d6252..469e1f53 100644
--- a/src/openglgraphics.h
+++ b/src/openglgraphics.h
@@ -46,6 +46,10 @@ class OpenGLGraphics : public Graphics
int width, int height,
bool useColor);
+ void drawImagePattern(Image *image,
+ int x, int y,
+ int w, int h);
+
void updateScreen();
void _beginDraw();
diff --git a/src/particle.cpp b/src/particle.cpp
index f021f6e5..21844f01 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -176,7 +176,8 @@ bool Particle::update()
mVelocity *= mBounce;
mVelocity.z = -mVelocity.z;
}
- else {
+ else
+ {
mAlive = false;
}
}
@@ -184,16 +185,12 @@ bool Particle::update()
// Update child emitters
if ((mLifetimePast-1)%Particle::emitterSkip == 0)
{
- for ( EmitterIterator e = mChildEmitters.begin();
- e != mChildEmitters.end();
- e++
- )
+ for (EmitterIterator e = mChildEmitters.begin();
+ e != mChildEmitters.end(); e++)
{
Particles newParticles = (*e)->createParticles(mLifetimePast);
- for ( ParticleIterator p = newParticles.begin();
- p != newParticles.end();
- p++
- )
+ for (ParticleIterator p = newParticles.begin();
+ p != newParticles.end(); p++)
{
(*p)->moveBy(mPos);
mChildParticles.push_back (*p);
@@ -218,7 +215,9 @@ bool Particle::update()
if ((*p)->update())
{
p++;
- } else {
+ }
+ else
+ {
delete (*p);
p = mChildParticles.erase(p);
}
@@ -236,8 +235,7 @@ void Particle::moveBy(const Vector &change)
{
mPos += change;
for (ParticleIterator p = mChildParticles.begin();
- p != mChildParticles.end();
- p++)
+ p != mChildParticles.end(); p++)
{
if ((*p)->doesFollow())
{
@@ -278,20 +276,21 @@ Particle *Particle::addEffect(const std::string &particleEffectFile,
xmlNodePtr node;
// Animation
- if ((node = XML::findFirstChildByName(
- effectChildNode, "animation"))) {
+ if ((node = XML::findFirstChildByName(effectChildNode, "animation")))
+ {
newParticle = new AnimationParticle(mMap, node);
}
// Image
- else if ((node = XML::findFirstChildByName(
- effectChildNode, "image"))) {
+ else if ((node = XML::findFirstChildByName(effectChildNode, "image")))
+ {
Image *img= resman->getImage((const char*)
node->xmlChildrenNode->content);
newParticle = new ImageParticle(mMap, img);
}
// Other
- else {
+ else
+ {
newParticle = new Particle(mMap);
}
@@ -314,7 +313,8 @@ Particle *Particle::addEffect(const std::string &particleEffectFile,
continue;
ParticleEmitter *newEmitter;
- newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap, rotation);
+ newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap,
+ rotation);
newParticle->addEmitter(newEmitter);
}
@@ -324,12 +324,11 @@ Particle *Particle::addEffect(const std::string &particleEffectFile,
return newParticle;
}
-Particle *Particle::addTextSplashEffect(const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font, int x, int y)
+Particle *Particle::addTextSplashEffect(const std::string &text, int x, int y,
+ const gcn::Color *color,
+ gcn::Font *font, bool outline)
{
- Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB,
- font);
+ Particle *newParticle = new TextParticle(mMap, text, color, font, outline);
newParticle->moveTo(x, y);
newParticle->setVelocity(((rand() % 100) - 50) / 200.0f, // X
((rand() % 100) - 50) / 200.0f, // Y
@@ -345,11 +344,11 @@ Particle *Particle::addTextSplashEffect(const std::string &text,
}
Particle *Particle::addTextRiseFadeOutEffect(const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font,
- int x, int y)
+ int x, int y,
+ const gcn::Color *color,
+ gcn::Font *font, bool outline)
{
- Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB, font);
+ Particle *newParticle = new TextParticle(mMap, text, color, font, outline);
newParticle->moveTo(x, y);
newParticle->setVelocity(0.0f, 0.0f, 0.5f);
newParticle->setGravity(0.0015f);
diff --git a/src/particle.h b/src/particle.h
index 008c343b..f3f5571a 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -105,17 +105,16 @@ class Particle : public Sprite
/**
* Creates a standalone text particle.
*/
- Particle *addTextSplashEffect(const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font, int x, int y);
+ Particle *addTextSplashEffect(const std::string &text, int x, int y,
+ const gcn::Color *color, gcn::Font *font,
+ bool outline = false);
/**
* Creates a standalone text particle.
*/
Particle *addTextRiseFadeOutEffect(const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font,
- int x, int y);
+ int x, int y, const gcn::Color *color, gcn::Font *font,
+ bool outline = false);
/**
* Adds an emitter to the particle.
diff --git a/src/player.cpp b/src/player.cpp
index 09eec0d1..8754e986 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -24,9 +24,13 @@
#ifdef TMWSERV_SUPPORT
#include "guild.h"
#endif
+#include "localplayer.h"
+#include "particle.h"
#include "player.h"
#include "text.h"
+#include "gui/palette.h"
+
#include "resources/colordb.h"
#include "resources/itemdb.h"
@@ -52,17 +56,19 @@ void Player::setName(const std::string &name)
{
if (mIsGM)
{
- mNameColor = 0x009000;
+ mNameColor = &guiPalette->getColor(Palette::GM);
mName = new FlashText("(GM) " + name, mPx + NAME_X_OFFSET, mPy +
NAME_Y_OFFSET, gcn::Graphics::CENTER,
- gcn::Color(0, 255, 0));
+ &guiPalette->getColor(Palette::GM_NAME));
}
else
{
- mNameColor = 0x202020;
+ mNameColor = &guiPalette->getColor(Palette::PLAYER);
mName = new FlashText(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
gcn::Graphics::CENTER,
- gcn::Color(255, 255, 255));
+ (this == player_node) ?
+ &guiPalette->getColor(Palette::SELF) :
+ &guiPalette->getColor(Palette::PC));
}
Being::setName(name);
}
@@ -94,7 +100,10 @@ void Player::logic()
break;
case ATTACK:
+ int rotation = 0;
+ std::string particleEffect = "";
int frames = 4;
+
if (mEquippedWeapon &&
mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW)
{
@@ -103,6 +112,26 @@ void Player::logic()
mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
+ //attack particle effect
+ if (mEquippedWeapon)
+ particleEffect = mEquippedWeapon->getParticleEffect();
+
+ if (!particleEffect.empty() && mParticleEffects && mFrame == 1)
+ {
+ switch (mDirection)
+ {
+ case DOWN: rotation = 0; break;
+ case LEFT: rotation = 90; break;
+ case UP: rotation = 180; break;
+ case RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect("graphics/particles/" +
+ particleEffect, 0, 0, rotation);
+ controlParticle(p);
+ }
+
if (mFrame >= frames)
nextStep();
diff --git a/src/player_relations.cpp b/src/player_relations.cpp
index c82876e1..ef2ef1bc 100644
--- a/src/player_relations.cpp
+++ b/src/player_relations.cpp
@@ -28,6 +28,8 @@
#include "player.h"
#include "player_relations.h"
+#include "utils/dtor.h"
+
#define PLAYER_IGNORE_STRATEGY_NOP "nop"
#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0"
#define DEFAULT_IGNORE_STRATEGY PLAYER_IGNORE_STRATEGY_EMOTE0
@@ -37,7 +39,6 @@
#define IGNORE_EMOTE_TIME 100
-
// (De)serialisation class
class PlayerConfSerialiser : public ConfigurationListManager<std::pair<std::string, PlayerRelation *>,
std::map<std::string, PlayerRelation *> *>
@@ -92,6 +93,11 @@ PlayerRelationsManager::PlayerRelationsManager() :
{
}
+PlayerRelationsManager::~PlayerRelationsManager()
+{
+ delete_all(mIgnoreStrategies);
+}
+
void PlayerRelationsManager::clear()
{
std::vector<std::string> *names = getPlayers();
@@ -345,24 +351,23 @@ private:
-static std::vector<PlayerIgnoreStrategy *> player_ignore_strategies;
-
std::vector<PlayerIgnoreStrategy *> *
PlayerRelationsManager::getPlayerIgnoreStrategies()
{
- if (player_ignore_strategies.size() == 0) {
+ if (mIgnoreStrategies.size() == 0)
+ {
// not initialised yet?
- player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE,
- "floating '...' bubble",
- PLAYER_IGNORE_STRATEGY_EMOTE0));
- player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE + 1,
- "floating bubble",
- "emote1"));
- player_ignore_strategies.push_back(new PIS_nothing());
- player_ignore_strategies.push_back(new PIS_dotdotdot());
- player_ignore_strategies.push_back(new PIS_blinkname());
+ mIgnoreStrategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE,
+ "floating '...' bubble",
+ PLAYER_IGNORE_STRATEGY_EMOTE0));
+ mIgnoreStrategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE + 1,
+ "floating bubble",
+ "emote1"));
+ mIgnoreStrategies.push_back(new PIS_nothing());
+ mIgnoreStrategies.push_back(new PIS_dotdotdot());
+ mIgnoreStrategies.push_back(new PIS_blinkname());
}
- return &player_ignore_strategies;
+ return &mIgnoreStrategies;
}
diff --git a/src/player_relations.h b/src/player_relations.h
index 1eb4ede6..a6c6a115 100644
--- a/src/player_relations.h
+++ b/src/player_relations.h
@@ -94,6 +94,7 @@ class PlayerRelationsManager
{
public:
PlayerRelationsManager();
+ ~PlayerRelationsManager();
/**
* Initialise player relations manager (load config file etc.)
@@ -142,7 +143,6 @@ public:
*/
void removePlayer(const std::string &name);
-
/**
* Retrieves the default permissions.
*/
@@ -153,8 +153,6 @@ public:
*/
void setDefault(unsigned int permissions);
-
-
/**
* Retrieves all known player ignore strategies.
*
@@ -232,6 +230,7 @@ private:
PlayerIgnoreStrategy *mIgnoreStrategy;
std::map<std::string, PlayerRelation *> mRelations;
std::list<PlayerRelationsListener *> mListeners;
+ std::vector<PlayerIgnoreStrategy *> mIgnoreStrategies;
};
diff --git a/src/resources/dye.cpp b/src/resources/dye.cpp
index 22bd2411..1e4fd2fd 100644
--- a/src/resources/dye.cpp
+++ b/src/resources/dye.cpp
@@ -25,7 +25,7 @@
#include "../log.h"
-Palette::Palette(const std::string &description)
+DyePalette::DyePalette(const std::string &description)
{
int size = description.length();
if (size == 0) return;
@@ -62,7 +62,7 @@ Palette::Palette(const std::string &description)
logger->log("Error, invalid embedded palette: %s", description.c_str());
}
-void Palette::getColor(int intensity, int color[3]) const
+void DyePalette::getColor(int intensity, int color[3]) const
{
if (intensity == 0)
{
@@ -111,7 +111,7 @@ void Palette::getColor(int intensity, int color[3]) const
Dye::Dye(const std::string &description)
{
for (int i = 0; i < 7; ++i)
- mPalettes[i] = 0;
+ mDyePalettes[i] = 0;
if (description.empty()) return;
@@ -141,7 +141,7 @@ Dye::Dye(const std::string &description)
logger->log("Error, invalid dye: %s", description.c_str());
return;
}
- mPalettes[i] = new Palette(description.substr(pos + 2, next_pos - pos - 2));
+ mDyePalettes[i] = new DyePalette(description.substr(pos + 2, next_pos - pos - 2));
++next_pos;
}
while (next_pos < length);
@@ -150,7 +150,7 @@ Dye::Dye(const std::string &description)
Dye::~Dye()
{
for (int i = 0; i < 7; ++i)
- delete mPalettes[i];
+ delete mDyePalettes[i];
}
void Dye::update(int color[3]) const
@@ -170,8 +170,8 @@ void Dye::update(int color[3]) const
int i = (color[0] != 0) | ((color[1] != 0) << 1) | ((color[2] != 0) << 2);
- if (mPalettes[i - 1])
- mPalettes[i - 1]->getColor(cmax, color);
+ if (mDyePalettes[i - 1])
+ mDyePalettes[i - 1]->getColor(cmax, color);
}
void Dye::instantiate(std::string &target, const std::string &palettes)
diff --git a/src/resources/dye.h b/src/resources/dye.h
index 3cef334a..d0d010bc 100644
--- a/src/resources/dye.h
+++ b/src/resources/dye.h
@@ -28,7 +28,7 @@
/**
* Class for performing a linear interpolation between colors.
*/
-class Palette
+class DyePalette
{
public:
@@ -37,7 +37,7 @@ class Palette
* The string is either a file name or a sequence of hexadecimal RGB
* values separated by ',' and starting with '#'.
*/
- Palette(const std::string &pallete);
+ DyePalette(const std::string &pallete);
/**
* Gets a pixel color depending on its intensity.
@@ -89,7 +89,7 @@ class Dye
*
* Red, Green, Yellow, Blue, Magenta, White (or rather gray).
*/
- Palette *mPalettes[7];
+ DyePalette *mDyePalettes[7];
};
#endif
diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp
index 5e9a146c..5bc8407a 100644
--- a/src/resources/emotedb.cpp
+++ b/src/resources/emotedb.cpp
@@ -21,6 +21,7 @@
#include "emotedb.h"
+#include "../animatedsprite.h"
#include "../log.h"
#include "../utils/xml.h"
@@ -41,9 +42,8 @@ void EmoteDB::load()
mLastEmote = 0;
EmoteSprite *unknownSprite = new EmoteSprite;
- unknownSprite->sprite = "error.xml";
+ unknownSprite->sprite = AnimatedSprite::load("error.xml");
unknownSprite->name = "unknown";
- unknownSprite->variant = 0;
mUnknown.sprites.push_back(unknownSprite);
logger->log("Initializing emote database...");
@@ -77,8 +77,10 @@ void EmoteDB::load()
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
EmoteSprite *currentSprite = new EmoteSprite;
- currentSprite->sprite = (const char*) spriteNode->xmlChildrenNode->content;
- currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ std::string file = "graphics/sprites/" + (std::string)
+ (const char*) spriteNode->xmlChildrenNode->content;
+ currentSprite->sprite = AnimatedSprite::load(file,
+ XML::getProperty(spriteNode, "variant", 0));
currentInfo->sprites.push_back(currentSprite);
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
@@ -102,6 +104,7 @@ void EmoteDB::unload()
{
while (!i->second->sprites.empty())
{
+ delete i->second->sprites.front()->sprite;
delete i->second->sprites.front();
i->second->sprites.pop_front();
}
@@ -112,6 +115,7 @@ void EmoteDB::unload()
while (!mUnknown.sprites.empty())
{
+ delete mUnknown.sprites.front()->sprite;
delete mUnknown.sprites.front();
mUnknown.sprites.pop_front();
}
@@ -119,21 +123,27 @@ void EmoteDB::unload()
mLoaded = false;
}
-const EmoteInfo& EmoteDB::get(int id)
+const EmoteInfo *EmoteDB::get(int id)
{
EmoteInfosIterator i = mEmoteInfos.find(id);
if (i == mEmoteInfos.end())
{
logger->log("EmoteDB: Warning, unknown emote ID %d requested", id);
- return mUnknown;
+ return &mUnknown;
}
else
{
- return *(i->second);
+ return i->second;
}
}
+const AnimatedSprite* EmoteDB::getAnimation(int id)
+{
+ const EmoteInfo *info = get(id);
+ return info->sprites.front()->sprite;
+}
+
const int& EmoteDB::getLast()
{
return mLastEmote;
diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h
index ad21722a..691881c8 100644
--- a/src/resources/emotedb.h
+++ b/src/resources/emotedb.h
@@ -26,11 +26,12 @@
#include <map>
#include <string>
+class AnimatedSprite;
+
struct EmoteSprite
{
- std::string sprite;
+ const AnimatedSprite *sprite;
std::string name;
- int variant;
};
struct EmoteInfo
@@ -50,7 +51,9 @@ namespace EmoteDB
void unload();
- const EmoteInfo& get(int id);
+ const EmoteInfo *get(int id);
+
+ const AnimatedSprite *getAnimation(int id);
const int& getLast();
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index 7a7e6ac8..b696389f 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -25,6 +25,7 @@
#include "image.h"
#include "../log.h"
+#include "../position.h"
#ifdef USE_OPENGL
bool Image::mUseOpenGL = false;
@@ -46,8 +47,7 @@ Image::Image(SDL_Surface *image):
}
#ifdef USE_OPENGL
-Image::Image(GLuint glimage, int width, int height,
- int texWidth, int texHeight):
+Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight):
mGLImage(glimage),
mTexWidth(texWidth),
mTexHeight(texHeight),
@@ -315,6 +315,81 @@ void Image::setAlpha(float a)
}
}
+Image* Image::merge(Image* image, const Position& pos)
+{
+ SDL_Surface* surface = new SDL_Surface(*(image->mImage));
+
+ Uint32 surface_pix, cur_pix;
+ Uint8 r, g, b, a, p_r, p_g, p_b, p_a;
+ double f_a, f_ca, f_pa;
+ SDL_PixelFormat *current_fmt = mImage->format;
+ SDL_PixelFormat *surface_fmt = surface->format;
+ int current_offset, surface_offset;
+ Position offset(0, 0);
+
+ SDL_LockSurface(surface);
+ SDL_LockSurface(mImage);
+ // for each pixel lines of a source image
+ for (offset.x = (pos.x > 0 ? 0 : -pos.x); offset.x < image->getWidth() &&
+ pos.x + offset.x < getWidth(); offset.x++)
+ {
+ for (offset.y = (pos.y > 0 ? 0 : -pos.y); offset.y < image->getHeight()
+ && pos.y + offset.y < getHeight(); offset.y++)
+ {
+ // Computing offset on both images
+ current_offset = (pos.y + offset.y) * getWidth() + pos.x + offset.x;
+ surface_offset = offset.y * surface->w + offset.x;
+
+ // Retrieving a pixel to merge
+ surface_pix = ((Uint32*) surface->pixels)[surface_offset];
+ cur_pix = ((Uint32*) mImage->pixels)[current_offset];
+
+ // Retreiving each channel of the pixel using pixel format
+ r = (Uint8)(((surface_pix & surface_fmt->Rmask) >>
+ surface_fmt->Rshift) << surface_fmt->Rloss);
+ g = (Uint8)(((surface_pix & surface_fmt->Gmask) >>
+ surface_fmt->Gshift) << surface_fmt->Gloss);
+ b = (Uint8)(((surface_pix & surface_fmt->Bmask) >>
+ surface_fmt->Bshift) << surface_fmt->Bloss);
+ a = (Uint8)(((surface_pix & surface_fmt->Amask) >>
+ surface_fmt->Ashift) << surface_fmt->Aloss);
+
+ // Retreiving previous alpha value
+ p_a = (Uint8)(((cur_pix & current_fmt->Amask) >>
+ current_fmt->Ashift) << current_fmt->Aloss);
+
+ // new pixel with no alpha or nothing on previous pixel
+ if (a == SDL_ALPHA_OPAQUE || (p_a == 0 && a > 0))
+ ((Uint32 *)(surface->pixels))[current_offset] =
+ SDL_MapRGBA(current_fmt, r, g, b, a);
+ else if (a > 0)
+ { // alpha is lower => merge color with previous value
+ f_a = (double) a / 255.0;
+ f_ca = 1.0 - f_a;
+ f_pa = (double) p_a / 255.0;
+ p_r = (Uint8)(((cur_pix & current_fmt->Rmask) >>
+ current_fmt->Rshift) << current_fmt->Rloss);
+ p_g = (Uint8)(((cur_pix & current_fmt->Gmask) >>
+ current_fmt->Gshift) << current_fmt->Gloss);
+ p_b = (Uint8)(((cur_pix & current_fmt->Bmask) >>
+ current_fmt->Bshift) << current_fmt->Bloss);
+ r = (Uint8)((double) p_r * f_ca * f_pa + (double)r * f_a);
+ g = (Uint8)((double) p_g * f_ca * f_pa + (double)g * f_a);
+ b = (Uint8)((double) p_b * f_ca * f_pa + (double)b * f_a);
+ a = (a > p_a ? a : p_a);
+ ((Uint32 *)(surface->pixels))[current_offset] =
+ SDL_MapRGBA(current_fmt, r, g, b, a);
+ }
+ }
+ }
+ SDL_UnlockSurface(surface);
+ SDL_UnlockSurface(mImage);
+
+ Image* newImage = new Image(surface);
+
+ return newImage;
+}
+
float Image::getAlpha()
{
return mAlpha;
diff --git a/src/resources/image.h b/src/resources/image.h
index 3160add8..260aeeba 100644
--- a/src/resources/image.h
+++ b/src/resources/image.h
@@ -40,6 +40,7 @@
#include "resource.h"
class Dye;
+class Position;
/**
* Defines a class for loading and storing images.
@@ -129,6 +130,15 @@ class Image : public Resource
static void setLoadAsOpenGL(bool useOpenGL);
#endif
+ /**
+ * Merges two image SDL_Surfaces together. This is for SDL use only, as
+ * reducing the number of surfaces that SDL has to render can cut down
+ * on the number of blit operations necessary, which in turn can help
+ * improve overall framerates. Don't use unless you are using it to
+ * reduce the number of overall layers that need to be drawn through SDL.
+ */
+ Image* merge(Image* image, const Position& pos);
+
protected:
/**
* Constructor.
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 7304f8a7..f7162db5 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -175,6 +175,10 @@ void ItemDB::load()
{
if (xmlStrEqual(itemChild->name, BAD_CAST "sprite"))
{
+ std::string attackParticle = XML::getProperty(
+ itemChild, "particle-effect", "");
+ itemInfo->setParticleEffect(attackParticle);
+
loadSpriteRef(itemInfo, itemChild);
}
else if (xmlStrEqual(itemChild->name, BAD_CAST "sound"))
@@ -204,9 +208,12 @@ void ItemDB::load()
if (param == error_value) \
logger->log("ItemDB: Missing " #param " attribute for item %i!",id)
- CHECK_PARAM(name, "");
+ if (id >= 0)
+ {
+ CHECK_PARAM(name, "");
+ CHECK_PARAM(description, "");
+ }
CHECK_PARAM(image, "");
- CHECK_PARAM(description, "");
// CHECK_PARAM(effect, "");
// CHECK_PARAM(type, 0);
// CHECK_PARAM(weight, 0);
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index 10749c9e..51b39876 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -138,6 +138,11 @@ class ItemInfo
const std::string& getName() const
{ return mName; }
+ void setParticleEffect(const std::string &particleEffect)
+ { mParticle = particleEffect; }
+
+ std::string getParticleEffect() const { return mParticle; }
+
void setImageName(const std::string &imageName)
{ mImageName = imageName; }
@@ -198,22 +203,23 @@ class ItemInfo
const std::string& getSound(EquipmentSoundEvent event) const;
protected:
- std::string mImageName; /**< The filename of the icon image. */
+ std::string mImageName; /**< The filename of the icon image. */
std::string mName;
- std::string mDescription; /**< Short description. */
- std::string mEffect; /**< Description of effects. */
+ std::string mDescription; /**< Short description. */
+ std::string mEffect; /**< Description of effects. */
#ifdef TMWSERV_SUPPORT
- char mType; /**< Item type. */
+ char mType; /**< Item type. */
#else
- std::string mType; /**< Item type. */
+ std::string mType; /**< Item type. */
#endif
- short mWeight; /**< Weight in grams. */
- int mView; /**< Item ID of how this item looks. */
- int mId; /**< Item ID */
+ std::string mParticle; /**< Particle effect used with this item */
+ short mWeight; /**< Weight in grams. */
+ int mView; /**< Item ID of how this item looks. */
+ int mId; /**< Item ID */
// Equipment related members
- SpriteAction mAttackType; /**< Attack type, in case of weapon. */
- int mAttackRange; /**< Attack range, will be zero if non weapon. */
+ SpriteAction mAttackType; /**< Attack type, in case of weapon. */
+ int mAttackRange; /**< Attack range, will be zero if non weapon. */
/** Maps gender to sprite filenames. */
std::map<int, std::string> mAnimationFiles;
diff --git a/src/shopitem.cpp b/src/shopitem.cpp
index 6547aaf1..ee55799f 100644
--- a/src/shopitem.cpp
+++ b/src/shopitem.cpp
@@ -23,10 +23,62 @@
#include "units.h"
-ShopItem::ShopItem(int id, int quantity, int price):
- Item(id, quantity),
- mPrice(price)
+ShopItem::ShopItem (int inventoryIndex, int id,
+ int quantity, int price) :
+ Item (id, 0), mPrice(price)
{
mDisplayName = getInfo().getName() +
" (" + Units::formatCurrency(mPrice).c_str() + ")";
+ setInvIndex(inventoryIndex);
+ addDuplicate(inventoryIndex, quantity);
+}
+
+ShopItem::ShopItem (int id, int price) : Item (id, 0), mPrice(price)
+{
+ mDisplayName = getInfo().getName() +
+ " (" + Units::formatCurrency(mPrice).c_str() + ")";
+ setInvIndex(-1);
+ addDuplicate(-1, 0);
+}
+
+ShopItem::~ShopItem()
+{
+ /** Clear all remaining duplicates on Object destruction. */
+ while (!mDuplicates.empty())
+ {
+ delete mDuplicates.top();
+ mDuplicates.pop();
+ }
+}
+
+void ShopItem::addDuplicate(int inventoryIndex, int quantity)
+{
+ DuplicateItem* di = new DuplicateItem;
+ di->inventoryIndex = inventoryIndex;
+ di->quantity = quantity;
+ mDuplicates.push(di);
+ mQuantity += quantity;
+}
+
+
+void ShopItem::addDuplicate()
+{
+ DuplicateItem* di = new DuplicateItem;
+ di->inventoryIndex = -1;
+ di->quantity = 0;
+ mDuplicates.push(di);
+}
+
+int ShopItem::sellCurrentDuplicate(int quantity)
+{
+ DuplicateItem* dupl = mDuplicates.top();
+ int sellCount = quantity <= dupl->quantity ? quantity : dupl->quantity;
+ dupl->quantity -= sellCount;
+ mQuantity -= sellCount;
+ if (dupl->quantity == 0)
+ {
+ delete dupl;
+ mDuplicates.pop();
+ }
+ return sellCount;
}
diff --git a/src/shopitem.h b/src/shopitem.h
index 50af4991..08a5c8d2 100644
--- a/src/shopitem.h
+++ b/src/shopitem.h
@@ -22,27 +22,100 @@
#ifndef _SHOPITEM_H
#define _SHOPITEM_H
+#include <stack>
+
#include "item.h"
/**
- * Represents an item in a shop inventory.
+ * Represents an item in a shop inventory. It can store quantity and inventory
+ * indices of duplicate entries in the shop as well.
*/
class ShopItem : public Item
{
public:
/**
- * Constructor.
+ * Constructor. Creates a new ShopItem.
+ *
+ * @param inventoryIndex the inventory index of the item
+ * @param id the id of the item
+ * @param quantity number of available copies of the item
+ * @param price price of the item
+ */
+ ShopItem(int inventoryIndex, int id, int quantity, int price);
+
+ /**
+ * Constructor. Creates a new ShopItem. Inventory index will be set to
+ * -1 and quantity to 0.
+ *
+ * @param id the id of the item
+ * @param price price of the item
+ */
+ ShopItem(int id, int price);
+
+ /**
+ * Destructor.
+ */
+ ~ShopItem();
+
+ /**
+ * Add a duplicate. Id and price will be taken from this item.
+ *
+ * @param inventoryIndex the inventory index of the item
+ * @param quantity number of available copies of the item
+ */
+ void addDuplicate (int inventoryIndex, int quantity);
+
+ /**
+ * Add a duplicate. Id and price will be taken from this item.
+ * Needed for compatibility with ShopDuplicateItems (see) class
+ * documentation).
*/
- ShopItem(int id, int quantity, int price);
+ void addDuplicate ();
+
+ /**
+ * Gets the quantity of the currently topmost duplicate.
+ *
+ * @return the quantity of the currently topmost duplicate
+ */
+ int getCurrentQuantity() {
+ return mDuplicates.empty() ? 0 : mDuplicates.top()->quantity;
+ }
+
+ /**
+ * Gets the inventory index of the currently topmost duplicate.
+ *
+ * @return the inventory index of the currently topmost duplicate
+ */
+ int getCurrentInvIndex() {
+ return mDuplicates.empty() ? mInvIndex :
+ mDuplicates.top()->inventoryIndex;
+ }
+
+ /**
+ * Reduces the quantity of the topmost duplicate by the specified
+ * amount. Also reduces the total quantity of this DuplicateItem.
+ * Empty duplicates are automatically removed.
+ *
+ * If the amount is bigger than the quantity of the current topmost,
+ * only sell as much as possible. Returns the amount actually sold (do
+ * not ignore the return value!)
+ *
+ * @return the amount, that actually was sold.
+ */
+ int sellCurrentDuplicate(int quantity);
/**
* Gets the price of the item.
+ *
+ * @return the price of the item
*/
int getPrice() const
{ return mPrice; }
/**
- * Gets the display name for in the shop list.
+ * Gets the display name for the item in the shop list.
+ *
+ * @return the display name for the item in the shop list
*/
const std::string& getDisplayName() const
{ return mDisplayName; }
@@ -50,6 +123,15 @@ class ShopItem : public Item
protected:
int mPrice;
std::string mDisplayName;
+
+ /**
+ * Struct to keep track of duplicates.
+ */
+ typedef struct {
+ int inventoryIndex;
+ int quantity;
+ } DuplicateItem;
+ std::stack<DuplicateItem*> mDuplicates; /** <-- Stores duplicates */
};
#endif
diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp
index c0d689f0..70e8d59f 100644
--- a/src/statuseffect.cpp
+++ b/src/statuseffect.cpp
@@ -92,7 +92,6 @@ static std::map<int, int> blockEffectIndexMap;
int StatusEffect::blockEffectIndexToEffectIndex(int blockIndex)
{
- load();
if (blockEffectIndexMap.find(blockIndex) == blockEffectIndexMap.end())
return -1;
return blockEffectIndexMap[blockIndex];
@@ -100,27 +99,16 @@ int StatusEffect::blockEffectIndexToEffectIndex(int blockIndex)
StatusEffect *StatusEffect::getStatusEffect(int index, bool enabling)
{
- load();
return statusEffects[enabling][index];
}
StatusEffect *StatusEffect::getStunEffect(int index, bool enabling)
{
- load();
return stunEffects[enabling][index];
}
-static bool status_effects_loaded = false;
-
-
-
void StatusEffect::load()
{
- if (status_effects_loaded)
- return;
-
- status_effects_loaded = true;
-
XML::Document doc(STATUS_EFFECTS_FILE);
xmlNodePtr rootNode = doc.rootNode();
@@ -168,3 +156,19 @@ void StatusEffect::load()
}
}
}
+
+void unloadMap(std::map<int, StatusEffect *> map)
+{
+ std::map<int, StatusEffect *>::iterator it;
+
+ for (it = map.begin(); it != map.end(); it++)
+ delete (*it).second;
+}
+
+void StatusEffect::unload()
+{
+ unloadMap(statusEffects[0]);
+ unloadMap(statusEffects[1]);
+ unloadMap(stunEffects[0]);
+ unloadMap(stunEffects[1]);
+} \ No newline at end of file
diff --git a/src/statuseffect.h b/src/statuseffect.h
index 16fed69a..f1af93d2 100644
--- a/src/statuseffect.h
+++ b/src/statuseffect.h
@@ -94,9 +94,11 @@ public:
*/
static int blockEffectIndexToEffectIndex(int blocKIndex);
-private:
static void load();
+ static void unload();
+private:
+
std::string mMessage;
std::string mSFXEffect;
std::string mParticleEffect;
diff --git a/src/text.cpp b/src/text.cpp
index cb4587d3..83bd6c24 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -30,6 +30,8 @@
#include "resources/image.h"
#include "gui/gui.h"
+#include "gui/palette.h"
+#include "gui/textrenderer.h"
int Text::mInstances = 0;
ImageRect Text::mBubble;
@@ -37,7 +39,7 @@ Image *Text::mBubbleArrow;
Text::Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color color, bool isSpeech) :
+ const gcn::Color* color, bool isSpeech) :
mText(text),
mColor(color),
mIsSpeech(isSpeech)
@@ -129,42 +131,14 @@ void Text::draw(gcn::Graphics *graphics, int xOff, int yOff)
*/
}
- // Text shadow
- graphics->setColor(gcn::Color(0, 0, 0));
- graphics->drawText(mText, mX - xOff + 1, mY - yOff + 1,
- gcn::Graphics::LEFT);
-
- if (!mIsSpeech) {
- graphics->setColor(gcn::Color(0, 0, 0, 64));
- /*
- // TODO: Reanable when we can draw it nicely in software mode
- graphics->drawText(mText, mX - xOff + 2, mY - yOff + 2,
- gcn::Graphics::LEFT);
- graphics->drawText(mText, mX - xOff + 1, mY - yOff + 2,
- gcn::Graphics::LEFT);
- graphics->drawText(mText, mX - xOff + 2, mY - yOff + 1,
- gcn::Graphics::LEFT);
- */
-
- // Text outline
- graphics->setColor(gcn::Color(0, 0, 0));
- graphics->drawText(mText, mX - xOff + 1, mY - yOff,
- gcn::Graphics::LEFT);
- graphics->drawText(mText, mX - xOff - 1, mY - yOff,
- gcn::Graphics::LEFT);
- graphics->drawText(mText, mX - xOff, mY - yOff + 1,
- gcn::Graphics::LEFT);
- graphics->drawText(mText, mX - xOff, mY - yOff - 1,
- gcn::Graphics::LEFT);
- }
-
- graphics->setColor(mColor);
- graphics->drawText(mText, mX - xOff, mY - yOff, gcn::Graphics::LEFT);
+ TextRenderer::renderText(graphics, mText,
+ mX - xOff, mY - yOff, gcn::Graphics::LEFT,
+ *mColor, boldFont, !mIsSpeech, true);
}
FlashText::FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color color) :
+ const gcn::Color *color) :
Text(text, x, y, alignment, color),
mTime(0)
{
@@ -175,9 +149,7 @@ void FlashText::draw(gcn::Graphics *graphics, int xOff, int yOff)
if (mTime)
{
if ((--mTime & 4) == 0)
- {
return;
- }
}
Text::draw(graphics, xOff, yOff);
}
diff --git a/src/text.h b/src/text.h
index 6e121da7..a96096cc 100644
--- a/src/text.h
+++ b/src/text.h
@@ -40,7 +40,7 @@ class Text
*/
Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color color, bool isSpeech = false);
+ const gcn::Color *color, bool isSpeech = false);
/**
* Destructor. The text is removed from the screen.
@@ -65,7 +65,7 @@ class Text
int mXOffset; /**< The offset of mX from the desired x. */
static int mInstances; /**< Instances of text. */
std::string mText; /**< The text to display. */
- gcn::Color mColor; /**< The color of the text. */
+ const gcn::Color *mColor; /**< The color of the text. */
bool mIsSpeech; /**< Is this text a speech bubble? */
protected:
@@ -78,7 +78,7 @@ class FlashText : public Text
public:
FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color color);
+ const gcn::Color* color);
/**
* Remove the text from the screen
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index f38c32ce..04b7abe1 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -21,18 +21,18 @@
#include <guichan/color.hpp>
-#include "graphics.h"
#include "textparticle.h"
+#include "gui/textrenderer.h"
+
TextParticle::TextParticle(Map *map, const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font):
+ const gcn::Color* color,
+ gcn::Font *font, bool outline):
Particle(map),
mText(text),
mTextFont(font),
- mColorR(colorR),
- mColorG(colorG),
- mColorB(colorB)
+ mColor(color),
+ mOutline(outline)
{
}
@@ -58,7 +58,7 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
alpha /= mFadeIn;
}
- graphics->setFont(mTextFont);
- graphics->setColor(gcn::Color(mColorR, mColorG, mColorB, (int)alpha));
- graphics->drawText(mText, screenX, screenY, gcn::Graphics::CENTER);
+ TextRenderer::renderText(graphics, mText,
+ screenX, screenY, gcn::Graphics::CENTER,
+ *mColor, mTextFont, mOutline, false, (int) alpha);
}
diff --git a/src/textparticle.h b/src/textparticle.h
index 76c247bf..8b7d3e01 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -32,8 +32,8 @@ class TextParticle : public Particle
* Constructor.
*/
TextParticle(Map *map, const std::string &text,
- int colorR, int colorG, int colorB,
- gcn::Font *font);
+ const gcn::Color* color,
+ gcn::Font *font, bool outline = false);
/**
* Draws the particle image.
@@ -47,7 +47,8 @@ class TextParticle : public Particle
private:
std::string mText; /**< Text of the particle. */
gcn::Font *mTextFont; /**< Font used for drawing the text. */
- int mColorR, mColorG, mColorB; /**< Color used for drawing the text. */
+ const gcn::Color* mColor; /**< Color used for drawing the text. */
+ bool mOutline; /**< Make the text better readable */
};
#endif
diff --git a/src/units.cpp b/src/units.cpp
index 4f8b95f0..7e8d8e6a 100644
--- a/src/units.cpp
+++ b/src/units.cpp
@@ -164,8 +164,8 @@ std::string formatUnit(int value, int type)
struct UnitLevel ul;
double amount = ud.conversion * value;
- // Shortcut for 0
- if (value == 0) {
+ // Shortcut for 0; do the same for values less than 0 (for now)
+ if (value <= 0) {
ul = ud.levels[0];
return strprintf("0%s", ul.symbol.c_str());
} else {