summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/animatedsprite.cpp87
-rw-r--r--src/animatedsprite.h16
-rw-r--r--src/animation.cpp33
-rw-r--r--src/animation.h16
-rw-r--r--src/being.cpp25
-rw-r--r--src/beingmanager.cpp29
-rw-r--r--src/beingmanager.h19
-rw-r--r--src/engine.cpp4
-rw-r--r--src/floor_item.cpp4
-rw-r--r--src/game.cpp77
-rw-r--r--src/game.h17
-rw-r--r--src/gui/buy.cpp47
-rw-r--r--src/gui/buy.h12
-rw-r--r--src/gui/char_select.cpp22
-rw-r--r--src/gui/char_select.h2
-rw-r--r--src/gui/equipmentwindow.cpp4
-rw-r--r--src/gui/gui.cpp13
-rw-r--r--src/gui/inventorywindow.cpp58
-rw-r--r--src/gui/inventorywindow.h20
-rw-r--r--src/gui/itemcontainer.cpp35
-rw-r--r--src/gui/itemcontainer.h35
-rw-r--r--src/gui/listbox.cpp57
-rw-r--r--src/gui/listbox.h41
-rw-r--r--src/gui/minimap.cpp4
-rw-r--r--src/gui/playerbox.cpp2
-rw-r--r--src/gui/popupmenu.cpp2
-rw-r--r--src/gui/selectionlistener.h78
-rw-r--r--src/gui/sell.cpp40
-rw-r--r--src/gui/sell.h13
-rw-r--r--src/gui/setup.cpp4
-rw-r--r--src/gui/setup_video.cpp52
-rw-r--r--src/gui/setup_video.h4
-rw-r--r--src/gui/trade.cpp63
-rw-r--r--src/gui/trade.h10
-rw-r--r--src/gui/updatewindow.cpp18
-rw-r--r--src/gui/updatewindow.h5
-rw-r--r--src/gui/window.cpp12
-rw-r--r--src/item.h2
-rw-r--r--src/localplayer.h7
-rw-r--r--src/main.cpp108
-rw-r--r--src/map.cpp24
-rw-r--r--src/net/inventoryhandler.cpp11
-rw-r--r--src/resources/image.cpp21
-rw-r--r--src/resources/image.h7
-rw-r--r--src/resources/iteminfo.cpp31
-rw-r--r--src/resources/iteminfo.h34
-rw-r--r--src/resources/itemmanager.cpp9
-rw-r--r--src/resources/itemmanager.h8
-rw-r--r--src/tmw.rc8
50 files changed, 921 insertions, 332 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 01f8a3b2..b621c63e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,6 +2,8 @@ AUTOMAKE_OPTIONS = subdir-objects
bin_PROGRAMS = tmw
tmw_SOURCES = graphic/imagerect.h \
+ gui/widgets/dropdown.cpp \
+ gui/widgets/dropdown.h \
gui/browserbox.cpp \
gui/browserbox.h \
gui/buddywindow.cpp \
@@ -77,6 +79,7 @@ tmw_SOURCES = graphic/imagerect.h \
gui/register.h \
gui/scrollarea.cpp \
gui/scrollarea.h \
+ gui/selectionlistener.h \
gui/sell.cpp \
gui/sell.h \
gui/serverdialog.cpp \
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index f984d13f..3815f04a 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: animation.cpp 2430 2006-07-24 00:13:24Z b_lindeijer $
+ * $Id$
*/
#include "animatedsprite.h"
@@ -90,14 +90,9 @@ AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
// get action
else if (xmlStrEqual(node->name, BAD_CAST "action"))
{
- std::string name = getProperty(node, "name", "");
+ std::string actionName = getProperty(node, "name", "");
std::string imageset = getProperty(node, "imageset", "");
- if (name.empty())
- {
- logger->log("Warning: unnamed action in %s",
- animationFile.c_str());
- }
if (mSpritesets.find(imageset) == mSpritesets.end()) {
logger->log("Warning: imageset \"%s\" not defined in %s",
imageset.c_str(),
@@ -107,10 +102,25 @@ AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
continue;
}
- Action *action = new Action();
+ SpriteAction actionType = makeSpriteAction(actionName);
+ if (actionType == ACTION_INVALID)
+ {
+ logger->log("Warning: Unknown action \"%s\" defined in %s",
+ actionName.c_str(),
+ animationFile.c_str());
+ continue;
+ }
+ Action *action = new Action();
action->setSpriteset(mSpritesets[imageset]);
- mActions[makeSpriteAction(name)] = action;
+ mActions[actionType] = action;
+
+ // When first action set it as default direction
+ if (mActions.empty())
+ {
+ mActions[ACTION_DEFAULT] = action;
+ }
+
// get animations
for (xmlNodePtr animationNode = node->xmlChildrenNode;
@@ -121,9 +131,20 @@ AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
if (!xmlStrEqual(animationNode->name, BAD_CAST "animation"))
continue;
- std::string dir = getProperty(animationNode, "direction", "");
+ std::string directionName = getProperty(animationNode, "direction", "");
+
+ SpriteDirection directionType = makeSpriteDirection(directionName);
+ if (directionType == DIRECTION_INVALID)
+ {
+ logger->log("Warning: Unknown direction \"%s\" defined for action %s in %s",
+ directionName.c_str(),
+ actionName.c_str(),
+ animationFile.c_str());
+ continue;
+ }
+
Animation *animation = new Animation();
- action->setAnimation(makeSpriteDirection(dir), animation);
+ action->setAnimation(directionType, animation);
// Get animation phases
for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode;
@@ -156,12 +177,17 @@ AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
start++;
}
}
+ else if (xmlStrEqual(phaseNode->name, BAD_CAST "end"))
+ {
+ animation->addTerminator();
+ };
} // for phaseNode
} // for animationNode
} // if "<imageset>" else if "<action>"
} // for node
// Complete missing actions
+ substituteAction(ACTION_STAND, ACTION_DEFAULT);
substituteAction(ACTION_WALK, ACTION_STAND);
substituteAction(ACTION_WALK, ACTION_RUN);
substituteAction(ACTION_ATTACK, ACTION_STAND);
@@ -247,7 +273,7 @@ AnimatedSprite::reset()
}
void
-AnimatedSprite::play(SpriteAction action, int time)
+AnimatedSprite::play(SpriteAction action)
{
ActionIterator i = mActions.find(action);
@@ -262,31 +288,31 @@ AnimatedSprite::play(SpriteAction action, int time)
if (mAction != i->second)
{
mAction = i->second;
- mLastTime = 0;
- }
-
- if (!mAction || !time)
- mSpeed = 1.0f;
- else {
- int animationLength = mAction->getAnimation(mDirection)->getLength();
- mSpeed = (float) animationLength / time;
+ //mAction->reset();
}
}
void
AnimatedSprite::update(int time)
{
+ bool notFinished = true;
// Avoid freaking out at first frame or when tick_time overflows
if (time < mLastTime || mLastTime == 0)
mLastTime = time;
- // If not enough time have passed yet, do nothing
+ // If not enough time has passed yet, do nothing
if (time > mLastTime && mAction)
{
Animation *animation = mAction->getAnimation(mDirection);
- animation->update((unsigned int)((time - mLastTime) * mSpeed));
+ if (animation != NULL) {
+ notFinished = animation->update((unsigned int)(time - mLastTime));}
mLastTime = time;
}
+
+ if (!notFinished)
+ {
+ play(ACTION_STAND);
+ }
}
bool
@@ -296,6 +322,8 @@ AnimatedSprite::draw(Graphics* graphics, Sint32 posX, Sint32 posY) const
return false;
Animation *animation = mAction->getAnimation(mDirection);
+ if (animation == NULL) return false;
+
int phase = animation->getCurrentPhase();
if (phase < 0)
return false;
@@ -322,6 +350,9 @@ AnimatedSprite::getHeight() const
SpriteAction
AnimatedSprite::makeSpriteAction(const std::string& action)
{
+ if (action == "" || action == "default") {
+ return ACTION_DEFAULT;
+ }
if (action == "stand") {
return ACTION_STAND;
}
@@ -365,14 +396,17 @@ AnimatedSprite::makeSpriteAction(const std::string& action)
return ACTION_DEAD;
}
else {
- return ACTION_DEFAULT;
+ return ACTION_INVALID;
}
}
SpriteDirection
AnimatedSprite::makeSpriteDirection(const std::string& direction)
{
- if (direction == "up") {
+ if (direction == "" || direction == "default") {
+ return DIRECTION_DEFAULT;
+ }
+ else if (direction == "up") {
return DIRECTION_UP;
}
else if (direction == "left") {
@@ -381,7 +415,10 @@ AnimatedSprite::makeSpriteDirection(const std::string& direction)
else if (direction == "right") {
return DIRECTION_RIGHT;
}
- else {
+ else if (direction == "down") {
return DIRECTION_DOWN;
}
+ else {
+ return DIRECTION_INVALID;
+ };
}
diff --git a/src/animatedsprite.h b/src/animatedsprite.h
index b73bdb5c..bda612ab 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: animation.h 2430 2006-07-24 00:13:24Z b_lindeijer $
+ * $Id$
*/
#ifndef _TMW_ANIMATEDSPRITE_H
@@ -50,15 +50,18 @@ enum SpriteAction
ACTION_SIT,
ACTION_SLEEP,
ACTION_HURT,
- ACTION_DEAD
+ ACTION_DEAD,
+ ACTION_INVALID
};
enum SpriteDirection
{
- DIRECTION_DOWN = 0,
+ DIRECTION_DEFAULT = 0,
+ DIRECTION_DOWN,
DIRECTION_UP,
DIRECTION_LEFT,
- DIRECTION_RIGHT
+ DIRECTION_RIGHT,
+ DIRECTION_INVALID
};
/**
@@ -85,11 +88,10 @@ class AnimatedSprite
reset();
/**
- * Plays an action using the current direction that will have a
- * duration of the specified time, 0 means default.
+ * Plays an action using the current direction
*/
void
- play(SpriteAction action, int time = 0);
+ play(SpriteAction action);
/**
* Inform the animation of the passed time so that it can output the
diff --git a/src/animation.cpp b/src/animation.cpp
index c1b27ebd..98a4abb8 100644
--- a/src/animation.cpp
+++ b/src/animation.cpp
@@ -39,45 +39,68 @@ Animation::reset()
iCurrentPhase = mAnimationPhases.begin();
}
-void
+
+bool
Animation::update(unsigned int time)
{
mTime += time;
if (mAnimationPhases.empty())
- return;
+ return true;
+ if (isTerminator(*iCurrentPhase))
+ return false;
unsigned int delay = iCurrentPhase->delay;
- if (!delay)
- return;
while (mTime > delay)
{
+ if (!delay)
+ return true;
mTime -= delay;
iCurrentPhase++;
if (iCurrentPhase == mAnimationPhases.end())
{
iCurrentPhase = mAnimationPhases.begin();
}
+ if (isTerminator(*iCurrentPhase))
+ return false;
+ delay = iCurrentPhase->delay;
}
+ return true;
}
+
int
Animation::getCurrentPhase() const
{
return mAnimationPhases.empty() ? -1 : iCurrentPhase->image;
}
+
void
Animation::addPhase(int image, unsigned int delay, int offsetX, int offsetY)
{
//add new phase to animation list
- AnimationPhase newPhase = { image, delay, offsetX, offsetY };
+ AnimationPhase newPhase = { image, delay, offsetX, offsetY};
mAnimationPhases.push_back(newPhase);
//reset animation circle
iCurrentPhase = mAnimationPhases.begin();
}
+void
+Animation::addTerminator()
+{
+ AnimationPhase terminator = { -1, 0, 0, 0};
+ mAnimationPhases.push_back(terminator);
+ iCurrentPhase = mAnimationPhases.begin();
+}
+
+bool
+Animation::isTerminator(AnimationPhase candidate)
+{
+ return (candidate.image < 0);
+}
+
int
Animation::getLength()
{
diff --git a/src/animation.h b/src/animation.h
index 60dcd287..605d8cb1 100644
--- a/src/animation.h
+++ b/src/animation.h
@@ -61,10 +61,25 @@ class Animation
void
reset();
+ /**
+ * Appends a new animation at the end of the sequence
+ */
void
addPhase(int image, unsigned int delay, int offsetX, int offsetY);
+ /**
+ * Appends an animation terminator that states that the animation
+ * should not loop
+ */
void
+ addTerminator();
+
+ /**
+ * Updates animation phase.
+ * true indicates a still running animation while false indicates a
+ * finished animation
+ */
+ bool
update(unsigned int time);
int
@@ -89,6 +104,7 @@ class Animation
getLength();
protected:
+ static bool isTerminator(AnimationPhase);
std::list<AnimationPhase> mAnimationPhases;
std::list<AnimationPhase>::iterator iCurrentPhase;
unsigned int mTime;
diff --git a/src/being.cpp b/src/being.cpp
index 982b0ebf..4d542753 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -331,10 +331,24 @@ Being::setAction(Uint8 action)
currentAction = ACTION_ATTACK;
break;
}
+ for (int i = 0; i < VECTOREND_SPRITE; i++)
+ {
+ if (mSprites[i])
+ {
+ mSprites[i]->reset();
+ }
+ }
};
break;
case MONSTER_ATTACK:
currentAction = ACTION_ATTACK;
+ for (int i = 0; i < VECTOREND_SPRITE; i++)
+ {
+ if (mSprites[i])
+ {
+ mSprites[i]->reset();
+ }
+ }
break;
case DEAD:
currentAction = ACTION_DEAD;
@@ -346,16 +360,7 @@ Being::setAction(Uint8 action)
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
- if (!mSprites[i])
- continue;
-
- if (currentAction == ACTION_ATTACK ||
- currentAction == ACTION_ATTACK_STAB ||
- currentAction == ACTION_ATTACK_BOW)
- {
- mSprites[i]->play(currentAction, mAttackSpeed);
- }
- else
+ if (mSprites[i])
{
mSprites[i]->play(currentAction);
}
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index d2db055a..30b68ee2 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -113,9 +113,9 @@ Being* BeingManager::findBeing(Uint16 x, Uint16 y, Being::Type type)
return (i == mBeings.end()) ? NULL : *i;
}
-Beings* BeingManager::getAll()
+Beings& BeingManager::getAll()
{
- return &mBeings;
+ return mBeings;
}
void BeingManager::logic()
@@ -153,3 +153,28 @@ void BeingManager::clear()
mBeings.push_back(player_node);
}
}
+
+Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
+ Being::Type type)
+{
+ Being *closestBeing = NULL;
+ int dist = 0;
+
+ for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
+ {
+ Being *being = (*i);
+ int d = abs(being->mX - x) + abs(being->mY - y);
+
+ if ((being->getType() == type || type == Being::UNKNOWN)
+ && (d < dist || closestBeing == NULL) // it is closer
+ && being->mAction != Being::DEAD // no dead beings
+ && being->mAction != Being::MONSTER_DEAD
+ )
+ {
+ dist = d;
+ closestBeing = being;
+ }
+ }
+
+ return (maxdist >= dist) ? closestBeing : NULL;
+}
diff --git a/src/beingmanager.h b/src/beingmanager.h
index c32884a0..15a347de 100644
--- a/src/beingmanager.h
+++ b/src/beingmanager.h
@@ -46,29 +46,38 @@ class BeingManager
void setPlayer(LocalPlayer *player);
/**
- * Create a being and add it to the list of beings
+ * Create a being and add it to the list of beings.
*/
Being* createBeing(Uint16 id, Uint16 job);
/**
- * Remove a Being
+ * Remove a Being.
*/
void destroyBeing(Being *being);
/**
- * Return a specific id Being
+ * Return a specific id Being.
*/
Being* findBeing(Uint16 id);
/**
- * Return a being at specific coordinates
+ * Return a being at specific coordinates.
*/
Being* findBeing(Uint16 x, Uint16 y, Being::Type type = Being::UNKNOWN);
/**
+ * Return a being nearest to specific coordinates.
+ *
+ * \param maxdist maximal distance. If minimal distance is larger,
+ * no being is returned
+ */
+ Being* findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
+ Being::Type type = Being::UNKNOWN);
+
+ /**
* Returns the whole list of beings
*/
- Beings* getAll();
+ Beings& getAll();
/**
* Logic.
diff --git a/src/engine.cpp b/src/engine.cpp
index 253a8288..231313c4 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -266,8 +266,8 @@ void Engine::draw(Graphics *graphics)
}
// Draw player nickname, speech, and emotion sprite as needed
- Beings *beings = beingManager->getAll();
- for (BeingIterator i = beings->begin(); i != beings->end(); i++)
+ Beings &beings = beingManager->getAll();
+ for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
(*i)->drawSpeech(graphics, -camera_x, -camera_y);
(*i)->drawName(graphics, -camera_x, -camera_y);
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index edd5d4a7..9a179a21 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -42,7 +42,7 @@ FloorItem::FloorItem(unsigned int id,
mMap(map)
{
// Retrieve item image from item info
- mImage = itemDb->getItemInfo(itemId)->getImage();
+ mImage = itemDb->getItemInfo(itemId).getImage();
// Add ourselves to the map
mSpriteIterator = mMap->addSprite(this);
@@ -50,6 +50,6 @@ FloorItem::FloorItem(unsigned int id,
FloorItem::~FloorItem()
{
- // Remove and delete the representative sprite
+ // Remove ourselves from the map
mMap->removeSprite(mSpriteIterator);
}
diff --git a/src/game.cpp b/src/game.cpp
index f5ebe095..5e4c24c2 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -202,9 +202,9 @@ void createGuiWindows()
minimap->getHeight() + 30);*/
// Set initial window visibility
- chatWindow->setSticky(true);
- miniStatusWindow->setSticky(true);
- menuWindow->setSticky(true);
+// chatWindow->setSticky(true);
+// miniStatusWindow->setSticky(true);
+// menuWindow->setSticky(true);
chatWindow->setVisible(true);
miniStatusWindow->setVisible(true);
@@ -277,6 +277,10 @@ Game::Game():
SDL_AddTimer(10, nextTick, NULL); // Logic counter
SDL_AddTimer(1000, nextSecond, NULL); // Seconds counter
+ // Initialize frame limiting
+ config.addListener("fpslimit", this);
+ optionChanged("fpslimit");
+
// Initialize beings
beingManager->setPlayer(player_node);
@@ -339,12 +343,23 @@ bool saveScreenshot(SDL_Surface *screenshot)
return ImageWriter::writePNG(screenshot, filename.str());
}
+void Game::optionChanged(const std::string &name)
+{
+ int fpsLimit = (int) config.getValue("fpslimit", 0);
+
+ // Calculate new minimum frame time
+ mMinFrameTime = fpsLimit ? 1000 / fpsLimit : 0;
+
+ // Reset draw time to current time
+ mDrawTime = tick_time * 10;
+}
+
void Game::logic()
{
+ // mDrawTime has a higher granularity than gameTime in order to be able to
+ // work with minimum frame durations in milliseconds.
int gameTime = tick_time;
- int drawTime = tick_time * 10;
- int delta = 0;
- int fpsLimit = 0;
+ mDrawTime = tick_time * 10;
while (!done)
{
@@ -356,23 +371,35 @@ void Game::logic()
gameTime++;
}
+ // This is done because at some point tick_time will wrap.
gameTime = tick_time;
- fpsLimit = (int)config.getValue("fpslimit", 50);
- delta = fpsLimit ? 1000 / fpsLimit : 0;
-
- // Update the screen when application is active, delay otherwise
- if (SDL_GetAppState() & SDL_APPACTIVE &&
- (abs(tick_time * 10 - drawTime) >= delta))
+ // Update the screen when application is active, delay otherwise.
+ if (SDL_GetAppState() & SDL_APPACTIVE)
{
- frame++;
- engine->draw(graphics);
- graphics->updateScreen();
- drawTime += delta;
+ // Draw a frame if either frames are not limited or enough time has
+ // passed since the last frame.
+ if (!mMinFrameTime ||
+ get_elapsed_time(mDrawTime / 10) > mMinFrameTime)
+ {
+ frame++;
+ engine->draw(graphics);
+ graphics->updateScreen();
+ mDrawTime += mMinFrameTime;
+
+ // Make sure to wrap mDrawTime, since tick_time will wrap.
+ if (mDrawTime > MAX_TIME * 10)
+ mDrawTime -= MAX_TIME * 10;
+ }
+ else
+ {
+ SDL_Delay(10);
+ }
}
else
{
SDL_Delay(10);
+ mDrawTime = tick_time * 10;
}
// Handle network stuff
@@ -463,10 +490,7 @@ void Game::handleInput()
// Attempt to hide all windows
case SDLK_h:
- chatWindow->setVisible(false);
- miniStatusWindow->setVisible(false);
statusWindow->setVisible(false);
- menuWindow->setVisible(false);
buyDialog->setVisible(false);
sellDialog->setVisible(false);
buySellDialog->setVisible(false);
@@ -474,12 +498,9 @@ void Game::handleInput()
npcTextDialog->setVisible(false);
npcListDialog->setVisible(false);
skillDialog->setVisible(false);
- //newSkillWindow->setVisible(false);
setupWindow->setVisible(false);
equipmentWindow->setVisible(false);
chargeDialog->setVisible(false);
- tradeWindow->setVisible(false);
- //buddyWindow->setVisible(false);
helpWindow->setVisible(false);
debugWindow->setVisible(false);
break;
@@ -679,6 +700,18 @@ void Game::handleInput()
player_node->attack(target, newTarget);
}
+ // Target the nearest monster if 'a' pressed
+ if (keys[SDLK_a])
+ {
+ Being *target =
+ beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER);
+
+ if (target)
+ {
+ player_node->setTarget(target);
+ }
+ }
+
if (joystick)
{
if (joystick->buttonPressed(1))
diff --git a/src/game.h b/src/game.h
index 7330052a..19a6054a 100644
--- a/src/game.h
+++ b/src/game.h
@@ -27,6 +27,8 @@
#include <iosfwd>
#include <memory>
+#include "configlistener.h"
+
#define SPEECH_TIME 80
#define SPEECH_MAX_TIME 100
@@ -36,7 +38,7 @@ extern std::string map_path;
extern volatile int fps;
extern volatile int tick_time;
-class Game
+class Game : public ConfigListener
{
public:
Game();
@@ -46,7 +48,15 @@ class Game
void handleInput();
- protected:
+ void optionChanged(const std::string &name);
+
+ private:
+ /** Used to determine whether to draw the next frame. */
+ int mDrawTime;
+
+ /** The minimum frame time (used for frame limiting). */
+ int mMinFrameTime;
+
typedef std::auto_ptr<MessageHandler> MessageHandlerPtr;
MessageHandlerPtr mBeingHandler;
MessageHandlerPtr mBuySellHandler;
@@ -61,8 +71,7 @@ class Game
};
/**
- * Returns elapsed time. (Warning: very unsafe function, it supposes the delay
- * is always < 10 seconds)
+ * Returns elapsed time. (Warning: supposes the delay is always < 100 seconds)
*/
int get_elapsed_time(int start_time);
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 165fa7dc..ae779503 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -91,6 +91,7 @@ BuyDialog::BuyDialog():
mSlider->setEventId("slider");
mItemList->addActionListener(this);
+ mItemList->addSelectionListener(this);
mSlider->addActionListener(this);
add(mScrollArea);
@@ -140,7 +141,8 @@ void BuyDialog::addItem(short id, int price)
{
ITEM_SHOP item_shop;
- item_shop.name = itemDb->getItemInfo(id)->getName() + " " + toString(price) + " GP";
+ item_shop.name = itemDb->getItemInfo(id).getName() + " "
+ + toString(price) + " GP";
item_shop.price = price;
item_shop.id = id;
@@ -152,7 +154,8 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
{
int selectedItem = mItemList->getSelected();
- if (eventId == "item") {
+ if (eventId == "item")
+ {
// Reset amount of items and update labels
mAmountItems = 0;
mSlider->setValue(0);
@@ -175,23 +178,27 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
mIncreaseButton->setEnabled(mMaxItems > 0);
mSlider->setEnabled(mMaxItems > 0);
}
- else if (eventId == "quit") {
+ else if (eventId == "quit")
+ {
setVisible(false);
current_npc = 0;
}
// The following actions require a valid selection
- if (selectedItem < 0 || selectedItem >= int(mShopItems->size())) {
+ if (selectedItem < 0 || selectedItem >= int(mShopItems->size()))
+ {
return;
}
bool updateButtonsAndLabels = false;
- if (eventId == "slider") {
+ if (eventId == "slider")
+ {
mAmountItems = (int)(mSlider->getValue() * mMaxItems);
updateButtonsAndLabels = true;
}
- else if (eventId == "+") {
+ else if (eventId == "+")
+ {
if (mAmountItems < mMaxItems) {
mAmountItems++;
} else {
@@ -201,7 +208,8 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
mSlider->setValue(double(mAmountItems)/double(mMaxItems));
updateButtonsAndLabels = true;
}
- else if (eventId == "-") {
+ else if (eventId == "-")
+ {
if (mAmountItems > 0) {
mAmountItems--;
} else {
@@ -211,7 +219,7 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
mSlider->setValue(double(mAmountItems)/double(mMaxItems));
updateButtonsAndLabels = true;
}
- // TODO Actually we'd have a bug elsewhere if this check for the number
+ // 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 _obivous_ way in C++?
else if (eventId == "buy" && (mAmountItems > 0 &&
@@ -239,7 +247,8 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
}
// If anything has changed, we have to update the buttons and labels
- if (updateButtonsAndLabels) {
+ if (updateButtonsAndLabels)
+ {
// Update buttons
mIncreaseButton->setEnabled(mAmountItems < mMaxItems);
mDecreaseButton->setEnabled(mAmountItems > 0);
@@ -255,19 +264,21 @@ void BuyDialog::action(const std::string &eventId, gcn::Widget *widget)
}
}
-void BuyDialog::mouseClick(int x, int y, int button, int count)
+void BuyDialog::selectionChanged(const SelectionEvent &event)
{
- Window::mouseClick(x, y, button, count);
-
int selectedItem = mItemList->getSelected();
+
if (selectedItem > -1)
{
- int itemId = mShopItems->at(selectedItem).id;
- ItemInfo *itemInfo = itemDb->getItemInfo(itemId);
+ const ItemInfo &info =
+ itemDb->getItemInfo(mShopItems->at(selectedItem).id);
- mItemDescLabel->setCaption("Description: " +
- itemInfo->getDescription());
- mItemEffectLabel->setCaption("Effect: " +
- itemInfo->getEffect());
+ mItemDescLabel->setCaption("Description: " + info.getDescription());
+ mItemEffectLabel->setCaption("Effect: " + info.getEffect());
+ }
+ else
+ {
+ mItemDescLabel->setCaption("Description:");
+ mItemEffectLabel->setCaption("Effect:");
}
}
diff --git a/src/gui/buy.h b/src/gui/buy.h
index 0ddea4c4..f5c163e1 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -27,17 +27,19 @@
#include <guichan/actionlistener.hpp>
#include "window.h"
+#include "selectionlistener.h"
#include "../guichanfwd.h"
class ShopItems;
+class ListBox;
/**
* The buy dialog.
*
* \ingroup Interface
*/
-class BuyDialog : public Window, public gcn::ActionListener
+class BuyDialog : public Window, public gcn::ActionListener, SelectionListener
{
public:
/**
@@ -78,9 +80,11 @@ class BuyDialog : public Window, public gcn::ActionListener
int getNumberOfElements();
/**
- * Mouse callback
+ * Updates the labels according to the selected item.
+ *
+ * @see SelectionListener::selectionChanged
*/
- void mouseClick(int x, int y, int buton, int count);
+ void selectionChanged(const SelectionEvent &event);
/**
* Returns the name of item number i in the shop inventory.
@@ -92,7 +96,7 @@ class BuyDialog : public Window, public gcn::ActionListener
gcn::Button *mQuitButton;
gcn::Button *mIncreaseButton;
gcn::Button *mDecreaseButton;
- gcn::ListBox *mItemList;
+ ListBox *mItemList;
gcn::ScrollArea *mScrollArea;
gcn::Label *mItemDescLabel;
gcn::Label *mItemEffectLabel;
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index 042a5be8..3e6c4a5f 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -224,6 +224,28 @@ void CharSelectDialog::logic()
updatePlayerInfo();
}
+bool CharSelectDialog::selectByName(const std::string &name)
+{
+ if (mCharInfo->isLocked())
+ return false;
+
+ unsigned int oldPos = mCharInfo->getPos();
+
+ mCharInfo->select(0);
+ do {
+ LocalPlayer *player = mCharInfo->getEntry();
+
+ if (player && player->getName() == name)
+ return true;
+
+ mCharInfo->next();
+ } while (mCharInfo->getPos());
+
+ mCharInfo->select(oldPos);
+
+ return false;
+}
+
std::string CharSelectDialog::getName()
{
return mNameLabel->getCaption();
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index 06881bb5..6d9d1a83 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -54,6 +54,8 @@ class CharSelectDialog : public Window, public gcn::ActionListener
void logic();
+ bool selectByName(const std::string &name);
+
/**
* Returns name of selected player
*/
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index 2cbffde4..ec525c47 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -65,7 +65,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
continue;
}
- image = item->getInfo()->getImage();
+ image = item->getInfo().getImage();
dynamic_cast<Graphics*>(graphics)->drawImage(
image, 36 * (i % 4) + 10, 36 * (i / 4) + 25);
}
@@ -76,7 +76,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
return;
}
- image = item->getInfo()->getImage();
+ image = item->getInfo().getImage();
dynamic_cast<Graphics*>(graphics)->drawImage(image, 160, 25);
graphics->drawText(toString(item->getQuantity()), 170, 62,
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index ecf81712..33852f2b 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -322,6 +322,19 @@ Gui::mousePress(int mx, int my, int button)
}
}
}
+
+ if (button == gcn::MouseInput::MIDDLE)
+ {
+ // Find the being nearest to the clicked position
+ Being *target = beingManager->findNearestLivingBeing(
+ tilex, tiley,
+ 20, Being::MONSTER);
+
+ if (target)
+ {
+ player_node->setTarget(target);
+ }
+ }
}
void
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index 063e8836..ea0fd8c0 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -55,6 +55,8 @@ InventoryWindow::InventoryWindow():
mDropButton = new Button("Drop", "drop", this);
mItems = new ItemContainer(player_node->mInventory.get());
+ mItems->addSelectionListener(this);
+
mInvenScroll = new ScrollArea(mItems);
mInvenScroll->setPosition(8, 8);
mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
@@ -123,33 +125,46 @@ void InventoryWindow::action(const std::string &eventId, gcn::Widget *widget)
}
}
-void InventoryWindow::mouseClick(int x, int y, int button, int count)
+void InventoryWindow::selectionChanged(const SelectionEvent &event)
{
- Window::mouseClick(x, y, button, count);
-
Item *item = mItems->getItem();
- if (!item) {
- return;
+ // Update name, effect and description
+ if (!item)
+ {
+ mItemNameLabel->setCaption("Name:");
+ mItemEffectLabel->setCaption("Effect:");
+ mItemDescriptionLabel->setCaption("Description:");
+ }
+ else
+ {
+ const ItemInfo& itemInfo = item->getInfo();
+ std::string SomeText;
+ SomeText = "Name: " + itemInfo.getName();
+ mItemNameLabel->setCaption(SomeText);
+ SomeText = "Effect: " + itemInfo.getEffect();
+ mItemEffectLabel->setCaption(SomeText);
+ SomeText = "Description: " + itemInfo.getDescription();
+ mItemDescriptionLabel->setCaption(SomeText);
+
+ mItemNameLabel->adjustSize();
+ mItemEffectLabel->adjustSize();
+ mItemDescriptionLabel->adjustSize();
}
+}
- // Show Name and Description
- std::string SomeText;
- SomeText = "Name: " + item->getInfo()->getName();
- mItemNameLabel->setCaption(SomeText);
- mItemNameLabel->adjustSize();
- SomeText = "Effect: " + item->getInfo()->getEffect();
- mItemEffectLabel->setCaption(SomeText);
- mItemEffectLabel->adjustSize();
- SomeText = "Description: " + item->getInfo()->getDescription();
- mItemDescriptionLabel->setCaption(SomeText);
- mItemDescriptionLabel->adjustSize();
+void InventoryWindow::mouseClick(int x, int y, int button, int count)
+{
+ Window::mouseClick(x, y, button, count);
if (button == gcn::MouseInput::RIGHT)
{
- /*
- * convert relative to the window coordinates to
- * absolute screen coordinates
+ Item *item = mItems->getItem();
+
+ if (!item) return;
+
+ /* Convert relative to the window coordinates to
+ * absolute screen coordinates.
*/
int mx = x + getX();
int my = y + getY();
@@ -223,11 +238,6 @@ void InventoryWindow::loadWindowState()
updateWidgets();
}
-void InventoryWindow::setDefaultSize(int defaultX, int defaultY, int defaultWidth, int defaultHeight)
-{
- Window::setDefaultSize(defaultX, defaultY, defaultWidth, defaultHeight);
-}
-
void InventoryWindow::resetToDefaultSize()
{
Window::resetToDefaultSize();
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index da7a7ef2..d46e91e7 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -27,6 +27,7 @@
#include <guichan/actionlistener.hpp>
#include "window.h"
+#include "selectionlistener.h"
#include "../guichanfwd.h"
@@ -38,7 +39,7 @@ class ItemContainer;
*
* \ingroup Interface
*/
-class InventoryWindow : public Window, gcn::ActionListener
+class InventoryWindow : public Window, gcn::ActionListener, SelectionListener
{
public:
/**
@@ -47,14 +48,14 @@ class InventoryWindow : public Window, gcn::ActionListener
InventoryWindow();
/**
- * Logic (updates buttons and weight information)
+ * Logic (updates buttons and weight information).
*/
void logic();
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
void mouseClick(int x, int y, int button, int count);
@@ -64,14 +65,19 @@ class InventoryWindow : public Window, gcn::ActionListener
void loadWindowState();
- void setDefaultSize(int defaultX, int defaultY, int defaultWidth, int defaultHeight);
-
void resetToDefaultSize();
+ /**
+ * Updates labels to currently selected item.
+ *
+ * @see SelectionListener::selectionChanged.
+ */
+ void selectionChanged(const SelectionEvent &event);
+
private:
- void updateButtons(); /** Updates button states */
+ void updateButtons(); /**< Updates button states. */
- void updateWidgets(); /** Updates widgets size/position */
+ void updateWidgets(); /**< Updates widgets size/position. */
ItemContainer *mItems;
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index c7c55fd9..5bcd000d 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -25,6 +25,8 @@
#include <guichan/mouseinput.hpp>
+#include "selectionlistener.h"
+
#include "../graphics.h"
#include "../inventory.h"
#include "../item.h"
@@ -38,14 +40,14 @@
#include "../utils/tostring.h"
ItemContainer::ItemContainer(Inventory *inventory):
- mInventory(inventory)
+ mInventory(inventory),
+ mSelectedItem(NULL)
{
ResourceManager *resman = ResourceManager::getInstance();
mSelImg = resman->getImage("graphics/gui/selection.png");
if (!mSelImg) logger->error("Unable to load selection.png");
- mSelectedItem = 0; // No item selected
mMaxItems = mInventory->getLastUsedSlot() - 1; // Count from 0, usage from 2
addMouseListener(this);
@@ -84,7 +86,7 @@ void ItemContainer::draw(gcn::Graphics* graphics)
// sure somewhere else)
if (mSelectedItem && mSelectedItem->getQuantity() <= 0)
{
- mSelectedItem = 0;
+ selectNone();
}
/*
@@ -111,7 +113,7 @@ void ItemContainer::draw(gcn::Graphics* graphics)
// Draw item icon
Image* image;
- if ((image = item->getInfo()->getImage()) != NULL)
+ if ((image = item->getInfo().getImage()) != NULL)
{
dynamic_cast<Graphics*>(graphics)->drawImage(
image, itemX, itemY);
@@ -150,7 +152,28 @@ Item* ItemContainer::getItem()
void ItemContainer::selectNone()
{
- mSelectedItem = 0;
+ setSelectedItem(NULL);
+}
+
+void ItemContainer::setSelectedItem(Item *item)
+{
+ if (mSelectedItem != item)
+ {
+ mSelectedItem = item;
+ fireSelectionChangedEvent();
+ }
+}
+
+void ItemContainer::fireSelectionChangedEvent()
+{
+ SelectionEvent event(this);
+ SelectionListeners::iterator i_end = mListeners.end();
+ SelectionListeners::iterator i;
+
+ for (i = mListeners.begin(); i != i_end; ++i)
+ {
+ (*i)->selectionChanged(event);
+ }
}
void ItemContainer::mousePress(int mx, int my, int button)
@@ -166,6 +189,6 @@ void ItemContainer::mousePress(int mx, int my, int button)
if (index > INVENTORY_SIZE) {
index = INVENTORY_SIZE - 1;
}
- mSelectedItem = mInventory->getItem(index);
+ setSelectedItem(mInventory->getItem(index));
}
}
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index f52f37ec..a2d5f0f7 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -27,9 +27,12 @@
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
+#include <list>
+
class Image;
class Inventory;
class Item;
+class SelectionListener;
/**
* An item container. Used to show items in inventory and trade dialog.
@@ -76,16 +79,46 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener
Item* getItem();
/**
- * Set selected item to -1.
+ * Sets selected item to NULL.
*/
void selectNone();
+ /**
+ * Adds a listener to the list that's notified each time a change to
+ * the selection occurs.
+ */
+ void addSelectionListener(SelectionListener *listener)
+ {
+ mListeners.push_back(listener);
+ }
+
+ /**
+ * Removes a listener from the list that's notified each time a change
+ * to the selection occurs.
+ */
+ void removeSelectionListener(SelectionListener *listener)
+ {
+ mListeners.remove(listener);
+ }
+
private:
+ /**
+ * Sets the currently selected item.
+ */
+ void setSelectedItem(Item *item);
+
+ /**
+ * Sends out selection events to the list of selection listeners.
+ */
+ void fireSelectionChangedEvent();
+
Inventory *mInventory;
Image *mSelImg;
Item *mSelectedItem;
int mMaxItems;
+
+ std::list<SelectionListener*> mListeners;
};
#endif
diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp
index df03b81b..14626d06 100644
--- a/src/gui/listbox.cpp
+++ b/src/gui/listbox.cpp
@@ -23,12 +23,16 @@
#include "listbox.h"
+#include "selectionlistener.h"
+
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
#include <guichan/listmodel.hpp>
+#include <guichan/mouseinput.hpp>
ListBox::ListBox(gcn::ListModel *listModel):
- gcn::ListBox(listModel)
+ gcn::ListBox(listModel),
+ mMousePressed(false)
{
}
@@ -45,8 +49,8 @@ void ListBox::draw(gcn::Graphics *graphics)
// Draw rectangle below the selected list element
if (mSelected >= 0) {
- graphics->fillRectangle(
- gcn::Rectangle(0, fontHeight * mSelected, getWidth(), fontHeight));
+ graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
+ getWidth(), fontHeight));
}
// Draw the list elements
@@ -55,3 +59,50 @@ void ListBox::draw(gcn::Graphics *graphics)
graphics->drawText(mListModel->getElementAt(i), 1, y);
}
}
+
+void ListBox::setSelected(int selected)
+{
+ gcn::ListBox::setSelected(selected);
+ fireSelectionChangedEvent();
+}
+
+void ListBox::mousePress(int x, int y, int button)
+{
+ gcn::ListBox::mousePress(x, y, button);
+
+ if (button == gcn::MouseInput::LEFT && hasMouse())
+ {
+ mMousePressed = true;
+ }
+}
+
+void ListBox::mouseRelease(int x, int y, int button)
+{
+ gcn::ListBox::mouseRelease(x, y, button);
+
+ mMousePressed = false;
+}
+
+void ListBox::mouseMotion(int x, int y)
+{
+ gcn::ListBox::mouseMotion(x, y);
+
+ // Pretend mouse is pressed continuously while dragged. Causes list
+ // selection to be updated as is default in many GUIs.
+ if (mMousePressed)
+ {
+ mousePress(x, y, gcn::MouseInput::LEFT);
+ }
+}
+
+void ListBox::fireSelectionChangedEvent()
+{
+ SelectionEvent event(this);
+ SelectionListeners::iterator i_end = mListeners.end();
+ SelectionListeners::iterator i;
+
+ for (i = mListeners.begin(); i != i_end; ++i)
+ {
+ (*i)->selectionChanged(event);
+ }
+}
diff --git a/src/gui/listbox.h b/src/gui/listbox.h
index 5999f7a7..c1932f54 100644
--- a/src/gui/listbox.h
+++ b/src/gui/listbox.h
@@ -26,10 +26,12 @@
#include <guichan/widgets/listbox.hpp>
+class SelectionListener;
+
/**
* A list box, meant to be used inside a scroll area. Same as the Guichan list
* box except this one doesn't have a background, instead completely relying
- * on the scroll area.
+ * on the scroll area. It also adds selection listener functionality.
*
* \ingroup GUI
*/
@@ -45,6 +47,43 @@ class ListBox : public gcn::ListBox
* Draws the list box.
*/
void draw(gcn::Graphics *graphics);
+
+ void mousePress(int x, int y, int button);
+ void mouseRelease(int x, int y, int button);
+ void mouseMotion(int x, int y);
+
+ /**
+ * Adds a listener to the list that's notified each time a change to
+ * the selection occurs.
+ */
+ void addSelectionListener(SelectionListener *listener)
+ {
+ mListeners.push_back(listener);
+ }
+
+ /**
+ * Removes a listener from the list that's notified each time a change
+ * to the selection occurs.
+ */
+ void removeSelectionListener(SelectionListener *listener)
+ {
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Sets the index of the selected element.
+ */
+ void setSelected(int selected);
+
+ private:
+ /**
+ * Sends out selection events to the list of selection listeners.
+ */
+ void fireSelectionChangedEvent();
+
+ bool mMousePressed; /**< Keeps track of mouse pressed status. */
+
+ std::list<SelectionListener*> mListeners;
};
#endif
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index db6d4f15..69c5eb6e 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -76,10 +76,10 @@ void Minimap::draw(gcn::Graphics *graphics)
mMapImage, getPadding(), getTitleBarHeight());
}
- Beings *beings = beingManager->getAll();
+ Beings &beings = beingManager->getAll();
BeingIterator bi;
- for (bi = beings->begin(); bi != beings->end(); bi++)
+ for (bi = beings.begin(); bi != beings.end(); bi++)
{
Being *being = (*bi);
int dotSize = 1;
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index ba97d54c..46cd7e85 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -97,7 +97,7 @@ void PlayerBox::draw(gcn::Graphics *graphics)
if (mHairStyle > 0 && mHairColor < NR_HAIR_COLORS &&
mHairStyle < NR_HAIR_STYLES)
{
- int hf = 9 * mHairColor;
+ int hf = 5 * mHairColor;
if (hf >= 0 && hf < (int)hairset[mHairStyle]->size()) {
dynamic_cast<Graphics*>(graphics)->drawImage(
hairset[mHairStyle - 1]->get(hf), 35, 7);
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 59316de1..ab81f7d0 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -106,7 +106,7 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
mBrowserBox->clearRows();
// Floor item can be picked up (single option, candidate for removal)
- std::string name = itemDb->getItemInfo(mFloorItem->getItemId())->getName();
+ std::string name = itemDb->getItemInfo(mFloorItem->getItemId()).getName();
mBrowserBox->addRow("@@pickup|Pick Up " + name + "@@");
//browserBox->addRow("@@look|Look To@@");
diff --git a/src/gui/selectionlistener.h b/src/gui/selectionlistener.h
new file mode 100644
index 00000000..a2fc6533
--- /dev/null
+++ b/src/gui/selectionlistener.h
@@ -0,0 +1,78 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: selectionlistener.h 2651 2006-09-03 16:47:48Z b_lindeijer $
+ */
+
+#ifndef _TMW_SELECTIONLISTENER_H__
+#define _TMW_SELECTIONLISTENER_H__
+
+#include <guichan/widget.hpp>
+
+/**
+ * An event that characterizes a change in the current selection.
+ *
+ * \ingroup GUI
+ */
+class SelectionEvent
+{
+ public:
+ /**
+ * Constructor.
+ */
+ SelectionEvent(gcn::Widget *source):
+ mSource(source)
+ {
+ }
+
+ /**
+ * The widget from which the event originated.
+ */
+ gcn::Widget* getSource() const
+ {
+ return mSource;
+ }
+
+ private:
+ gcn::Widget *mSource;
+};
+
+/**
+ * The listener that's notified when a selection value changes.
+ *
+ * \ingroup GUI
+ */
+class SelectionListener
+{
+ public:
+ /**
+ * Virtual destructor.
+ */
+ virtual ~SelectionListener() {}
+
+ /**
+ * Called whenever the value of the selection changes.
+ */
+ virtual void selectionChanged(const SelectionEvent &event) = 0;
+};
+
+typedef std::list<SelectionListener*> SelectionListeners;
+
+#endif
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index 33813271..d6d8cad5 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -94,6 +94,7 @@ SellDialog::SellDialog():
mSlider->setEventId("mSlider");
mItemList->addActionListener(this);
+ mItemList->addSelectionListener(this);
mSlider->addActionListener(this);
add(scrollArea);
@@ -141,7 +142,7 @@ void SellDialog::addItem(Item *item, int price)
ITEM_SHOP item_shop;
- item_shop.name = item->getInfo()->getName() + " " + toString(price) + " GP";
+ item_shop.name = item->getInfo().getName() + " " + toString(price) + " GP";
item_shop.price = price;
item_shop.index = item->getInvIndex();
item_shop.id = item->getId();
@@ -155,7 +156,8 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
{
int selectedItem = mItemList->getSelected();
- if (eventId == "item") {
+ if (eventId == "item")
+ {
mAmountItems = 0;
mSlider->setValue(0);
mDecreaseButton->setEnabled(false);
@@ -188,19 +190,22 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
bool updateButtonsAndLabels = false;
- if (eventId == "mSlider") {
+ if (eventId == "mSlider")
+ {
mAmountItems = (int)(mSlider->getValue() * mMaxItems);
updateButtonsAndLabels = true;
}
- else if (eventId == "+") {
+ else if (eventId == "+")
+ {
assert(mAmountItems < mMaxItems);
mAmountItems++;
mSlider->setValue(double(mAmountItems)/double(mMaxItems));
updateButtonsAndLabels = true;
}
- else if (eventId == "-") {
+ else if (eventId == "-")
+ {
assert(mAmountItems > 0);
mAmountItems--;
@@ -208,7 +213,8 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
updateButtonsAndLabels = true;
}
- else if (eventId == "sell") {
+ else if (eventId == "sell")
+ {
// Attempt sell
assert(mAmountItems > 0 && mAmountItems <= mMaxItems);
@@ -234,7 +240,8 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
}
// If anything changed, we need to update the buttons and labels
- if (updateButtonsAndLabels) {
+ if (updateButtonsAndLabels)
+ {
// Update labels
mQuantityLabel->setCaption(toString(mAmountItems));
mQuantityLabel->adjustSize();
@@ -250,16 +257,21 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
}
}
-void SellDialog::mouseClick(int x, int y, int button, int count)
+void SellDialog::selectionChanged(const SelectionEvent &event)
{
- Window::mouseClick(x, y, button, count);
-
int selectedItem = mItemList->getSelected();
+
if (selectedItem > -1)
{
- mItemDescLabel->setCaption("Description: " +
- itemDb->getItemInfo(mShopItems->at(selectedItem).id)->getDescription());
- mItemEffectLabel->setCaption("Effect: " +
- itemDb->getItemInfo(mShopItems->at(selectedItem).id)->getEffect());
+ const ItemInfo &info =
+ itemDb->getItemInfo(mShopItems->at(selectedItem).id);
+
+ mItemDescLabel->setCaption("Description: " + info.getDescription());
+ mItemEffectLabel->setCaption("Effect: " + info.getEffect());
+ }
+ else
+ {
+ mItemDescLabel->setCaption("Description");
+ mItemEffectLabel->setCaption("Effect");
}
}
diff --git a/src/gui/sell.h b/src/gui/sell.h
index be5185bd..69f8b089 100644
--- a/src/gui/sell.h
+++ b/src/gui/sell.h
@@ -27,19 +27,20 @@
#include <guichan/actionlistener.hpp>
#include "window.h"
+#include "selectionlistener.h"
#include "../guichanfwd.h"
class Item;
class ShopItems;
-
+class ListBox;
/**
* The sell dialog.
*
* \ingroup Interface
*/
-class SellDialog : public Window, public gcn::ActionListener
+class SellDialog : public Window, gcn::ActionListener, SelectionListener
{
public:
/**
@@ -70,15 +71,17 @@ class SellDialog : public Window, public gcn::ActionListener
void action(const std::string& eventId, gcn::Widget* widget);
/**
- * Mouse callback
+ * Updates labels according to selected item.
+ *
+ * @see SelectionListener::selectionChanged
*/
- void mouseClick(int x, int y, int buton, int count);
+ void selectionChanged(const SelectionEvent &event);
private:
gcn::Button *mSellButton;
gcn::Button *mIncreaseButton;
gcn::Button *mDecreaseButton;
- gcn::ListBox *mItemList;
+ ListBox *mItemList;
gcn::Label *mMoneyLabel;
gcn::Label *mItemDescLabel;
gcn::Label *mItemEffectLabel;
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index d12ace75..78b10498 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -43,7 +43,7 @@ Setup::Setup():
Window("Setup")
{
int width = 230;
- int height = 225;
+ int height = 245;
setContentSize(width, height);
const char *buttonNames[] = {
@@ -58,7 +58,7 @@ Setup::Setup():
}
TabbedContainer *panel = new TabbedContainer();
- panel->setDimension(gcn::Rectangle(5, 5, 220, 185));
+ panel->setDimension(gcn::Rectangle(5, 5, 220, 205));
panel->setOpaque(false);
SetupTab *tab;
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 7c72975a..7a4aae03 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -106,7 +106,7 @@ Setup_Video::Setup_Video():
mOpenGLEnabled(config.getValue("opengl", 0)),
mCustomCursorEnabled(config.getValue("customcursor", 1)),
mOpacity(config.getValue("guialpha", 0.8)),
- mFps((int)config.getValue("fpslimit", 50)),
+ mFps((int)config.getValue("fpslimit", 60)),
mModeListModel(new ModeListModel()),
mModeList(new ListBox(mModeListModel)),
mFsCheckBox(new CheckBox("Full screen", mFullScreenEnabled)),
@@ -121,7 +121,10 @@ Setup_Video::Setup_Video():
mScrollLazinessField(new TextField()),
mOriginalScrollRadius((int) config.getValue("ScrollRadius", 32)),
mScrollRadiusSlider(new Slider(0, 128)),
- mScrollRadiusField(new TextField())
+ mScrollRadiusField(new TextField()),
+ mOverlayDetail((int) config.getValue("OverlayDetail", 2)),
+ mOverlayDetailSlider(new Slider(0, 2)),
+ mOverlayDetailField(new gcn::Label(""))
{
setOpaque(false);
@@ -163,6 +166,8 @@ Setup_Video::Setup_Video():
mScrollRadiusField->setEventId("scrollradiusfield");
mScrollLazinessSlider->setEventId("scrolllazinessslider");
mScrollLazinessField->setEventId("scrolllazinessfield");
+ mOverlayDetailSlider->setEventId("overlaydetailslider");
+ mOverlayDetailField->setEventId("overlaydetailfield");
mCustomCursorCheckBox->addActionListener(this);
mAlphaSlider->addActionListener(this);
@@ -173,6 +178,8 @@ Setup_Video::Setup_Video():
mScrollRadiusField->addKeyListener(this);
mScrollLazinessSlider->addActionListener(this);
mScrollLazinessField->addKeyListener(this);
+ mOverlayDetailSlider->addActionListener(this);
+ mOverlayDetailField->addKeyListener(this);
mScrollRadiusSlider->setDimension(gcn::Rectangle(10, 120, 75, 10));
gcn::Label *scrollRadiusLabel = new gcn::Label("Scroll radius");
@@ -190,6 +197,25 @@ Setup_Video::Setup_Video():
mScrollLazinessField->setText(toString(mOriginalScrollLaziness));
mScrollLazinessSlider->setValue(mOriginalScrollLaziness);
+ mOverlayDetailSlider->setDimension(gcn::Rectangle(10, 160, 75, 10));
+ gcn::Label *overlayDetailLabel = new gcn::Label("Ambient FX");
+ overlayDetailLabel->setPosition(90, 160);
+ mOverlayDetailField->setPosition(180, 160);
+ mOverlayDetailField->setWidth(30);
+ switch (mOverlayDetail)
+ {
+ case 0:
+ mOverlayDetailField->setCaption("off");
+ break;
+ case 1:
+ mOverlayDetailField->setCaption("low");
+ break;
+ case 2:
+ mOverlayDetailField->setCaption("high");
+ break;
+ }
+ mOverlayDetailSlider->setValue(mOverlayDetail);
+
add(scrollArea);
add(mFsCheckBox);
add(mOpenGLCheckBox);
@@ -205,6 +231,9 @@ Setup_Video::Setup_Video():
add(mScrollLazinessSlider);
add(scrollLazinessLabel);
add(mScrollLazinessField);
+ add(mOverlayDetailSlider);
+ add(overlayDetailLabel);
+ add(mOverlayDetailField);
}
Setup_Video::~Setup_Video()
@@ -258,6 +287,7 @@ void Setup_Video::apply()
mFullScreenEnabled = config.getValue("screen", 0);
mCustomCursorEnabled = config.getValue("customcursor", 1);
mOpacity = config.getValue("guialpha", 0.8);
+ mOverlayDetail = (int)config.getValue("OverlayDetail", 2);
mOpenGLEnabled = config.getValue("opengl", 0);
}
@@ -288,6 +318,7 @@ void Setup_Video::cancel()
mOpenGLCheckBox->setMarked(mOpenGLEnabled);
mCustomCursorCheckBox->setMarked(mCustomCursorEnabled);
mAlphaSlider->setValue(mOpacity);
+ mOverlayDetailSlider->setValue(mOverlayDetail);
mScrollRadiusField->setText(toString(mOriginalScrollRadius));
mScrollLazinessField->setText(toString(mOriginalScrollLaziness));
@@ -328,6 +359,23 @@ void Setup_Video::action(const std::string &event, gcn::Widget *widget)
mScrollLazinessField->setText(toString(val));
config.setValue("ScrollLaziness", val);
}
+ else if (event == "overlaydetailslider")
+ {
+ int val = (int)mOverlayDetailSlider->getValue();
+ switch (val)
+ {
+ case 0:
+ mOverlayDetailField->setCaption("off");
+ break;
+ case 1:
+ mOverlayDetailField->setCaption("low");
+ break;
+ case 2:
+ mOverlayDetailField->setCaption("high");
+ break;
+ }
+ config.setValue("OverlayDetail", val);
+ }
else if (event == "fpslimitcheckbox")
{
if (mFpsCheckBox->isMarked())
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index a3fd8884..482d1c65 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -73,6 +73,10 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
gcn::Slider *mScrollRadiusSlider;
gcn::TextField *mScrollRadiusField;
+ int mOverlayDetail;
+ gcn::Slider *mOverlayDetailSlider;
+ gcn::Label *mOverlayDetailField;
+
void
updateSliders(bool originalValues);
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 0cd49013..44efbdb1 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -58,12 +58,14 @@ TradeWindow::TradeWindow():
mTradeButton = new Button("Trade", "trade", this);
mMyItemContainer = new ItemContainer(mMyInventory.get());
+ mMyItemContainer->addSelectionListener(this);
mMyItemContainer->setPosition(2, 2);
mMyScroll = new ScrollArea(mMyItemContainer);
mMyScroll->setPosition(8, 8);
mPartnerItemContainer = new ItemContainer(mPartnerInventory.get());
+ mPartnerItemContainer->addSelectionListener(this);
mPartnerItemContainer->setPosition(2, 58);
mPartnerScroll = new ScrollArea(mPartnerItemContainer);
@@ -219,53 +221,54 @@ void TradeWindow::tradeItem(Item *item, int quantity)
outMsg.writeLong(quantity);
}
-void TradeWindow::mouseClick(int x, int y, int button, int count)
+void TradeWindow::selectionChanged(const SelectionEvent &event)
{
- Window::mouseClick(x, y, button, count);
-
Item *item;
- // mMyItems selected
- if (x >= mMyScroll->getX() + 3
- && x <= mMyScroll->getX() + mMyScroll->getWidth() - 10
- && y >= mMyScroll->getY() + 16
- && y <= mMyScroll->getY() + mMyScroll->getHeight() + 15
- && (item = mMyItemContainer->getItem()))
+ /* If an item is selected in one container, make sure no item is selected
+ * in the other container.
+ */
+ if (event.getSource() == mMyItemContainer &&
+ (item = mMyItemContainer->getItem()))
{
- mPartnerItemContainer->selectNone();
- // mPartnerItems selected
+ mPartnerItemContainer->selectNone();
}
- else if (x >= mPartnerScroll->getX() + 3
- && x <= mPartnerScroll->getX() + mPartnerScroll->getWidth() - 20
- && y >= mPartnerScroll->getY() + 16
- && y <= mPartnerScroll->getY() + mPartnerScroll->getHeight() + 15
- && (item = mPartnerItemContainer->getItem()))
+ else if ((item = mPartnerItemContainer->getItem()))
{
- mMyItemContainer->selectNone();
- } else {
- return;
+ mMyItemContainer->selectNone();
}
- // Show Name and Description
- std::string SomeText;
- SomeText = "Name: " + item->getInfo()->getName();
- mItemNameLabel->setCaption(SomeText);
- mItemNameLabel->adjustSize();
- SomeText = "Description: " + item->getInfo()->getDescription();
- mItemDescriptionLabel->setCaption(SomeText);
- mItemDescriptionLabel->adjustSize();
+ // Update name and description
+ if (!item)
+ {
+ mItemNameLabel->setCaption("Name:");
+ mItemDescriptionLabel->setCaption("Description:");
+ }
+ else
+ {
+ std::string SomeText;
+ SomeText = "Name: " + item->getInfo().getName();
+ mItemNameLabel->setCaption(SomeText);
+ mItemNameLabel->adjustSize();
+ SomeText = "Description: " + item->getInfo().getDescription();
+ mItemDescriptionLabel->setCaption(SomeText);
+ mItemDescriptionLabel->adjustSize();
+ }
}
void TradeWindow::action(const std::string &eventId, gcn::Widget *widget)
{
Item *item = inventoryWindow->getItem();
- if (eventId == "add") {
- if (!item) {
+ if (eventId == "add")
+ {
+ if (!item)
+ {
return;
}
- if (mMyInventory->getFreeSlot() < 1) {
+ if (mMyInventory->getFreeSlot() < 1)
+ {
return;
}
diff --git a/src/gui/trade.h b/src/gui/trade.h
index fe60aac5..ebd05a52 100644
--- a/src/gui/trade.h
+++ b/src/gui/trade.h
@@ -29,6 +29,7 @@
#include <guichan/actionlistener.hpp>
#include "window.h"
+#include "selectionlistener.h"
#include "../guichanfwd.h"
@@ -42,7 +43,7 @@ class ScrollArea;
*
* \ingroup Interface
*/
-class TradeWindow : public Window, gcn::ActionListener
+class TradeWindow : public Window, gcn::ActionListener, SelectionListener
{
public:
/**
@@ -102,14 +103,15 @@ class TradeWindow : public Window, gcn::ActionListener
tradeItem(Item *item, int quantity);
/**
- * Called on mouse click.
+ * Updates the labels and makes sure only one item is selected in
+ * either my inventory or partner inventory.
*/
- void mouseClick(int x, int y, int button, int count);
+ void selectionChanged(const SelectionEvent &event);
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
private:
typedef std::auto_ptr<Inventory> InventoryPtr;
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 77a026fe..00b10406 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -48,9 +48,9 @@ UpdaterWindow::UpdaterWindow():
Window("Updating..."),
mThread(NULL), mMutex(NULL), mDownloadStatus(UPDATE_NEWS),
mUpdateHost(""), mCurrentFile("news.txt"), mBasePath(""),
- mStoreInMemory(true), mDownloadComplete(true), mDownloadedBytes(0),
- mMemoryBuffer(NULL), mCurlError(new char[CURL_ERROR_SIZE]),
- mFileIndex(0)
+ mStoreInMemory(true), mDownloadComplete(true), mUserCancel(false),
+ mDownloadedBytes(0), mMemoryBuffer(NULL),
+ mCurlError(new char[CURL_ERROR_SIZE]), mFileIndex(0)
{
mCurlError[0] = 0;
@@ -133,6 +133,8 @@ void UpdaterWindow::action(const std::string &eventId, gcn::Widget *widget)
{
if (eventId == "cancel")
{
+ // Register the user cancel
+ mUserCancel=true;
// Skip the updating process
if (mDownloadStatus == UPDATE_COMPLETE)
{
@@ -329,7 +331,15 @@ void UpdaterWindow::logic()
case UPDATE_ERROR:
if (mThread)
{
- SDL_WaitThread(mThread, NULL);
+ if(mUserCancel){
+ // Kill the thread, because user has canceled
+ SDL_KillThread(mThread);
+ // Set the flag to false again
+ mUserCancel = false;
+ }
+ else{
+ SDL_WaitThread(mThread, NULL);
+ }
mThread = NULL;
}
addRow("");
diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h
index 8a168be8..5016036d 100644
--- a/src/gui/updatewindow.h
+++ b/src/gui/updatewindow.h
@@ -162,6 +162,11 @@ class UpdaterWindow : public Window, public gcn::ActionListener
bool mDownloadComplete;
/**
+ * Flag that show if the user has canceled the update
+ */
+ bool mUserCancel;
+
+ /**
* Byte count currently downloaded in mMemoryBuffer.
*/
int mDownloadedBytes;
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 2172baa8..c7860021 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -249,16 +249,18 @@ void Window::setSticky(bool sticky)
mSticky = sticky;
}
-bool Window::isSticky() {
+bool Window::isSticky()
+{
return mSticky;
}
-void Window::setVisible(bool visible) {
- if(isSticky())
+void Window::setVisible(bool visible)
+{
+ if (isSticky())
{
gcn::Window::setVisible(true);
- }
- else
+ }
+ else
{
gcn::Window::setVisible(visible);
}
diff --git a/src/item.h b/src/item.h
index c21f5ddf..1375886e 100644
--- a/src/item.h
+++ b/src/item.h
@@ -118,7 +118,7 @@ class Item
/**
* Returns information about this item type.
*/
- ItemInfo*
+ const ItemInfo&
getInfo() const { return itemDb->getItemInfo(mId); }
protected:
diff --git a/src/localplayer.h b/src/localplayer.h
index 7d5aef87..dbf2a147 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -96,12 +96,17 @@ class LocalPlayer : public Player
* Sets the trading state of the player, i.e. whether or not he is
* currently involved into some trade.
*/
- void setTrading(bool trading) { mTrading = trading; };
+ void setTrading(bool trading) { mTrading = trading; }
void attack(Being *target=NULL, bool keep=false);
void stopAttack();
Being* getTarget() const;
+ /**
+ * Sets the target being of the player.
+ */
+ void setTarget(Being* target) { mTarget = target; }
+
void walk(unsigned char dir);
/**
diff --git a/src/main.cpp b/src/main.cpp
index 9d2a1e64..f881ddad 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -108,6 +108,33 @@ namespace {
}
/**
+ * A structure holding the values of various options that can be passed from
+ * the command line.
+ */
+struct Options
+{
+ /**
+ * Constructor.
+ */
+ Options():
+ printHelp(false),
+ skipUpdate(false),
+ chooseDefault(false),
+ serverPort(0)
+ {};
+
+ bool printHelp;
+ bool skipUpdate;
+ bool chooseDefault;
+ std::string playername;
+ std::string password;
+ std::string configPath;
+
+ std::string serverName;
+ short serverPort;
+};
+
+/**
* Initializes the home directory. On UNIX and FreeBSD, ~/.tmw is used. On
* Windows and other systems we use the current working directory.
*/
@@ -133,7 +160,7 @@ void initHomeDir()
/**
* Initialize configuration.
*/
-void initConfiguration()
+void initConfiguration(const Options &options)
{
// Fill configuration with defaults
config.setValue("host", "animesites.de");
@@ -158,7 +185,10 @@ void initConfiguration()
// Checking if the configuration file exists... otherwise create it with
// default options.
FILE *tmwFile = 0;
- std::string configPath = homeDir + "/config.xml";
+ std::string configPath = options.configPath;
+ if (configPath == "") {
+ configPath = homeDir + "/config.xml";
+ }
tmwFile = fopen(configPath.c_str(), "r");
// If we can't read it, it doesn't exist !
@@ -176,7 +206,7 @@ void initConfiguration()
}
/**
- * Do all initialization stuff
+ * Do all initialization stuff.
*/
void init_engine()
{
@@ -279,7 +309,8 @@ void init_engine()
sound.init();
}
sound.setSfxVolume((int)config.getValue("sfxVolume", defaultSfxVolume));
- sound.setMusicVolume((int)config.getValue("musicVolume", defaultMusicVolume));
+ sound.setMusicVolume((int)config.getValue("musicVolume",
+ defaultMusicVolume));
}
catch (const char *err) {
state = STATE_ERROR;
@@ -311,33 +342,6 @@ void exit_engine()
ResourceManager::deleteInstance();
}
-/**
- * A structure holding the values of various options that can be passed from
- * the command line.
- */
-struct Options
-{
- /**
- * Constructor.
- */
- Options():
- printHelp(false),
- skipUpdate(false),
- chooseDefault(false),
- serverPort(0)
- {};
-
- bool printHelp;
- bool skipUpdate;
- bool chooseDefault;
- std::string playername;
- std::string password;
-
- std::string serverName;
- short serverPort;
-
-};
-
void printHelp()
{
std::cout
@@ -351,12 +355,13 @@ void printHelp()
<< std::endl
<< " -s --server : Login Server name or IP" << std::endl
<< " -o --port : Login Server Port" << std::endl
- << " -p --playername : Login with this player" << std::endl;
+ << " -p --playername : Login with this player" << std::endl
+ << " -C --configfile : Configuration file to use" << std::endl;
}
void parseOptions(int argc, char *argv[], Options &options)
{
- const char *optstring = "huU:P:Dp:s:o:";
+ const char *optstring = "huU:P:Dp:s:o:C:";
const struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
@@ -367,6 +372,7 @@ void parseOptions(int argc, char *argv[], Options &options)
{ "server", required_argument, 0, 's' },
{ "port", required_argument, 0, 'o' },
{ "playername", required_argument, 0, 'p' },
+ { "configfile", required_argument, 0, 'C' },
{ 0 }
};
@@ -403,6 +409,9 @@ void parseOptions(int argc, char *argv[], Options &options)
case 'p':
options.playername = optarg;
break;
+ case 'C':
+ options.configPath = optarg;
+ break;
}
}
}
@@ -480,6 +489,10 @@ void mapLogin(LoginData *loginData)
{
Network::registerHandler(&mapLoginHandler);
+ logger->log("Memorizing selected character %s",
+ player_node->getName().c_str());
+ config.setValue("lastCharacter", player_node->getName());
+
// Send connect messages with the magic token to game and chat servers
MessageOut gameServerConnect(PGMSG_CONNECT);
gameServerConnect.writeString(token, 32);
@@ -510,7 +523,7 @@ int main(int argc, char *argv[])
PHYSFS_init(argv[0]);
initHomeDir();
- initConfiguration();
+ initConfiguration(options);
// Configure logger
logger = new Logger();
@@ -721,23 +734,16 @@ int main(int argc, char *argv[])
case STATE_CHAR_SELECT:
logger->log("State: CHAR_SELECT");
currentDialog = new CharSelectDialog(&charInfo);
- if (options.playername != "") {
- n_character = 0;
- while (((CharSelectDialog*) currentDialog)->getName()
- != options.playername &&
- n_character < MAX_SLOT + 1)
- {
- ((CharSelectDialog*) currentDialog)->action("next",
- NULL);
- ((CharSelectDialog*) currentDialog)->updatePlayerInfo();
- n_character++;
- }
- n_character = MAX_SLOT + 1;
- }
- if (options.chooseDefault || options.playername != "") {
- ((CharSelectDialog*)currentDialog)->action("ok",
- NULL);
- }
+
+ if (((CharSelectDialog*)currentDialog)->
+ selectByName(options.playername))
+ options.chooseDefault = true;
+ else
+ ((CharSelectDialog*)currentDialog)->selectByName(
+ config.getValue("lastCharacter", ""));
+
+ if (options.chooseDefault)
+ ((CharSelectDialog*)currentDialog)->action("ok", NULL);
break;
case STATE_ERROR:
diff --git a/src/map.cpp b/src/map.cpp
index 5063a754..3ccaafc0 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -63,8 +63,11 @@ Map::Map(int width, int height, int tileWidth, int tileHeight):
mOnClosedList(1), mOnOpenList(2),
mLastScrollX(0.0f), mLastScrollY(0.0f)
{
- mMetaTiles = new MetaTile[mWidth * mHeight];
- mTiles = new Image*[mWidth * mHeight * 3];
+ int size = mWidth * mHeight;
+
+ mMetaTiles = new MetaTile[size];
+ mTiles = new Image*[size * 3];
+ std::fill_n(mTiles, size * 3, (Image*)0);
}
Map::~Map()
@@ -86,12 +89,17 @@ Map::~Map()
void
Map::setSize(int width, int height)
{
- mWidth = width;
- mHeight = height;
delete[] mMetaTiles;
delete[] mTiles;
- mMetaTiles = new MetaTile[mWidth * mHeight];
- mTiles = new Image*[mWidth * mHeight * 3];
+
+ mWidth = width;
+ mHeight = height;
+
+ int size = width * height;
+
+ mMetaTiles = new MetaTile[size];
+ mTiles = new Image*[size * 3];
+ std::fill_n(mTiles, size * 3, (Image*)0);
}
void
@@ -330,8 +338,8 @@ Map::getWalk(int x, int y)
/*
// Check for collision with a being
- Beings *beings = beingManager->getAll();
- for (BeingIterator i = beings->begin(); i != beings->end(); i++) {
+ Beings &beings = beingManager->getAll();
+ for (BeingIterator i = beings.begin(); i != beings.end(); i++) {
// job 45 is a portal, they don't collide
if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) {
return false;
diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp
index c4192bc5..3f7e8709 100644
--- a/src/net/inventoryhandler.cpp
+++ b/src/net/inventoryhandler.cpp
@@ -92,14 +92,9 @@ void InventoryHandler::handleMessage(MessageIn &msg)
if (msg.readByte()> 0) {
chatWindow->chatLog("Unable to pick up item", BY_SERVER);
} else {
- ItemInfo *itemInfo = itemDb->getItemInfo(itemId);
- if (itemInfo) {
- chatWindow->chatLog("You picked up a " +
- itemInfo->getName(), BY_SERVER);
- } else {
- chatWindow->chatLog("You picked up an unknown item",
- BY_SERVER);
- }
+ const ItemInfo &itemInfo = itemDb->getItemInfo(itemId);
+ chatWindow->chatLog("You picked up a " +
+ itemInfo.getName(), BY_SERVER);
player_node->addInvItem(index, itemId, amount, equipType != 0);
}
break;
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index 51899d3f..eb3a2409 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -260,11 +260,18 @@ void Image::unload()
{
mLoaded = false;
- if (!mImage) return;
+ if (mImage) {
+ // Free the image surface.
+ SDL_FreeSurface(mImage);
+ mImage = NULL;
+ }
- // Free the image surface.
- SDL_FreeSurface(mImage);
- mImage = NULL;
+#ifdef USE_OPENGL
+ if (mGLImage) {
+ glDeleteTextures(1, &mGLImage);
+ mGLImage = 0;
+ }
+#endif
}
Image *Image::getSubImage(int x, int y, int width, int height)
@@ -341,7 +348,11 @@ SubImage::SubImage(Image *parent, GLuint image,
SubImage::~SubImage()
{
- mImage = 0; // Avoid destruction of the image
+ // Avoid destruction of the image
+ mImage = 0;
+#ifdef USE_OPENGL
+ mGLImage = 0;
+#endif
mParent->decRef();
}
diff --git a/src/resources/image.h b/src/resources/image.h
index 78751394..a1ab7f48 100644
--- a/src/resources/image.h
+++ b/src/resources/image.h
@@ -28,6 +28,13 @@
#include <SDL.h>
#ifdef USE_OPENGL
+
+/* The definition of OpenGL extensions by SDL is giving problems with recent
+ * gl.h headers, since they also include these definitions. As we're not using
+ * extensions anyway it's safe to just disable the SDL version.
+ */
+#define NO_SDL_GLEXT
+
#include <SDL_opengl.h>
#endif
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index 5d39d832..b09d1cc0 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -23,22 +23,33 @@
#include "iteminfo.h"
#include "resourcemanager.h"
+#include "image.h"
-Image*
-ItemInfo::getImage() {
- if (mImage == NULL && mImageName != "") {
- mImage = ResourceManager::getInstance()->getImage(mImageName);
+
+ItemInfo::~ItemInfo()
+{
+ if (mImage != NULL)
+ {
+ mImage->decRef();
}
- return mImage;
}
void
-ItemInfo::setImage(const std::string &image) {
+ItemInfo::setImage(const std::string &image)
+{
mImageName = "graphics/items/" + image;
-}
-ItemInfo::~ItemInfo() {
- if (mImage != NULL){
- mImage->decRef();
+ if (mImageName != "")
+ {
+ if (mImage != NULL)
+ {
+ mImage->decRef();
+ }
+
+ mImage = ResourceManager::getInstance()->getImage(mImageName);
+ }
+ else
+ {
+ mImage = NULL;
}
}
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index afa2e857..9a04bb2e 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -26,7 +26,7 @@
#include <string>
-#include "image.h"
+class Image;
/**
* Defines a class for storing item infos.
@@ -40,8 +40,8 @@ class ItemInfo
* Constructor.
*/
ItemInfo():
- mImage(NULL),
mImageName(""),
+ mImage(NULL),
mArt(0),
mType(0),
mWeight(0),
@@ -53,19 +53,19 @@ class ItemInfo
setArt(short art) { mArt = art; }
short
- getArt() { return mArt; }
+ getArt() const { return mArt; }
void
setName(const std::string &name) { mName = name; }
- std::string
- getName() { return mName; }
+ const std::string&
+ getName() const { return mName; }
void
setImage(const std::string &image);
Image*
- getImage();
+ getImage() const { return mImage; }
void
setDescription(const std::string &description)
@@ -73,32 +73,32 @@ class ItemInfo
mDescription = description;
}
- std::string
- getDescription() { return mDescription; }
+ const std::string&
+ getDescription() const { return mDescription; }
void
setEffect(const std::string &effect) { mEffect = effect; }
- std::string
- getEffect() { return mEffect; }
+ const std::string&
+ getEffect() const { return mEffect; }
void
setType(short type) { mType = type; }
short
- getType() { return mType; }
+ getType() const { return mType; }
void
setWeight(short weight) { mWeight = weight; }
short
- getWeight() { return mWeight; }
+ getWeight() const { return mWeight; }
void
setSlot(char slot) { mSlot = slot; }
char
- getSlot() { return mSlot; }
+ getSlot() const { return mSlot; }
protected:
/**
@@ -106,8 +106,14 @@ class ItemInfo
*/
~ItemInfo();
- Image* mImage;
std::string mImageName;
+
+ /* TODO (BL): I do not think the item info should keep a reference to
+ * the item icon. It would probably be better if this was kept in the
+ * Item class, so that the images can be lazily instantiated and also
+ * unloaded when no longer used.
+ */
+ Image *mImage;
short mArt;
std::string mName;
std::string mDescription;
diff --git a/src/resources/itemmanager.cpp b/src/resources/itemmanager.cpp
index a497b3c8..7d0b13f2 100644
--- a/src/resources/itemmanager.cpp
+++ b/src/resources/itemmanager.cpp
@@ -41,8 +41,7 @@
ItemManager::ItemManager()
{
- mUnknown = new ItemInfo();
- mUnknown->setName("Unknown item");
+ mUnknown.setName("Unknown item");
ResourceManager *resman = ResourceManager::getInstance();
int size;
@@ -163,14 +162,12 @@ ItemManager::~ItemManager()
delete i->second;
}
mItemInfos.clear();
-
- delete mUnknown;
}
-ItemInfo*
+const ItemInfo&
ItemManager::getItemInfo(int id)
{
ItemInfoIterator i = mItemInfos.find(id);
- return (i != mItemInfos.end()) ? i->second : mUnknown;
+ return (i != mItemInfos.end()) ? *(i->second) : mUnknown;
}
diff --git a/src/resources/itemmanager.h b/src/resources/itemmanager.h
index 06eee507..b1f2b95c 100644
--- a/src/resources/itemmanager.h
+++ b/src/resources/itemmanager.h
@@ -24,9 +24,9 @@
#ifndef _TMW_ITEM_MANAGER_H
#define _TMW_ITEM_MANAGER_H
-#include <map>
+#include "iteminfo.h"
-class ItemInfo;
+#include <map>
/**
* Defines a class to load items database.
@@ -44,14 +44,14 @@ class ItemManager
*/
~ItemManager();
- ItemInfo *getItemInfo(int id);
+ const ItemInfo& getItemInfo(int id);
protected:
// Items database
typedef std::map<int, ItemInfo*> ItemInfos;
typedef ItemInfos::iterator ItemInfoIterator;
ItemInfos mItemInfos;
- ItemInfo *mUnknown;
+ ItemInfo mUnknown;
};
extern ItemManager *itemDb;
diff --git a/src/tmw.rc b/src/tmw.rc
index 31411b61..388b643d 100644
--- a/src/tmw.rc
+++ b/src/tmw.rc
@@ -7,8 +7,8 @@ A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/tmw-icon.ico"
// TO CHANGE VERSION INFORMATION, EDIT PROJECT OPTIONS...
//
1 VERSIONINFO
-FILEVERSION 0,0,20,0
-PRODUCTVERSION 0,0,20,0
+FILEVERSION 0,0,21,0
+PRODUCTVERSION 0,0,21,0
FILETYPE VFT_APP
{
BLOCK "StringFileInfo"
@@ -16,14 +16,14 @@ FILETYPE VFT_APP
BLOCK "040904E4"
{
VALUE "CompanyName", "The Mana World Development Team"
- VALUE "FileVersion", "0.0.20"
+ VALUE "FileVersion", "0.0.21"
VALUE "FileDescription", "The Mana World"
VALUE "InternalName", "tmw.exe"
VALUE "LegalCopyright", "2004-2006 (C)"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "tmw.exe"
VALUE "ProductName", "The Mana World MMORPG"
- VALUE "ProductVersion", "0.0.20"
+ VALUE "ProductVersion", "0.0.21"
}
}
BLOCK "VarFileInfo"