summaryrefslogtreecommitdiff
path: root/src/gui/viewport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/viewport.cpp')
-rw-r--r--src/gui/viewport.cpp368
1 files changed, 208 insertions, 160 deletions
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index b18b9b0b..0353fd44 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -21,16 +21,14 @@
#include "gui/viewport.h"
+#include "actorspritemanager.h"
#include "client.h"
-#include "beingmanager.h"
#include "configuration.h"
-#include "flooritemmanager.h"
#include "graphics.h"
#include "keyboardconfig.h"
#include "localplayer.h"
#include "map.h"
-#include "monster.h"
-#include "npc.h"
+#include "playerinfo.h"
#include "textmanager.h"
#include "gui/gui.h"
@@ -39,12 +37,14 @@
#include "gui/beingpopup.h"
#include "net/net.h"
+#include "net/playerhandler.h"
-#include "resources/monsterinfo.h"
#include "resources/resourcemanager.h"
#include "utils/stringutils.h"
+#include <cmath>
+
extern volatile int tick_time;
Viewport::Viewport():
@@ -53,7 +53,7 @@ Viewport::Viewport():
mMouseY(0),
mPixelViewX(0.0f),
mPixelViewY(0.0f),
- mShowDebugPath(false),
+ mDebugFlags(0),
mPlayerFollowMouse(false),
mLocalWalkTime(-1),
mHoverBeing(0),
@@ -62,18 +62,18 @@ Viewport::Viewport():
setOpaque(false);
addMouseListener(this);
- mScrollLaziness = (int) config.getValue("ScrollLaziness", 16);
- mScrollRadius = (int) config.getValue("ScrollRadius", 0);
- mScrollCenterOffsetX = (int) config.getValue("ScrollCenterOffsetX", 0);
- mScrollCenterOffsetY = (int) config.getValue("ScrollCenterOffsetY", 0);
-
- config.addListener("ScrollLaziness", this);
- config.addListener("ScrollRadius", this);
+ mScrollLaziness = config.getIntValue("ScrollLaziness");
+ mScrollRadius = config.getIntValue("ScrollRadius");
+ mScrollCenterOffsetX = config.getIntValue("ScrollCenterOffsetX");
+ mScrollCenterOffsetY = config.getIntValue("ScrollCenterOffsetY");
mPopupMenu = new PopupMenu;
mBeingPopup = new BeingPopup;
setFocusable(true);
+
+ listen(Event::ConfigChannel);
+ listen(Event::ActorSpriteChannel);
}
Viewport::~Viewport()
@@ -124,9 +124,9 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
if (mScrollLaziness < 1)
mScrollLaziness = 1; // Avoids division by zero
- // Apply lazy scrolling
while (lastTick < tick_time)
{
+ // Apply lazy scrolling
if (player_x > mPixelViewX + mScrollRadius)
{
mPixelViewX += (player_x - mPixelViewX - mScrollRadius) /
@@ -147,6 +147,22 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
mPixelViewY += (player_y - mPixelViewY + mScrollRadius) /
mScrollLaziness;
}
+
+ // manage shake effect
+ for (ShakeEffects::iterator i = mShakeEffects.begin();
+ i != mShakeEffects.end();
+ i++)
+ {
+ // apply the effect to viewport
+ mPixelViewX += i->x *= -i->decay;
+ mPixelViewY += i->y *= -i->decay;
+ // check death conditions
+ if (abs(i->x) + abs(i->y) < 1.0f ||
+ (i->duration > 0 && --i->duration == 0))
+ {
+ i = mShakeEffects.erase(i);
+ }
+ }
lastTick++;
}
@@ -183,14 +199,15 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
{
mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
- if (mShowDebugPath)
+ if (mDebugFlags)
{
- mMap->drawCollision(graphics,
- (int) mPixelViewX,
- (int) mPixelViewY,
- mShowDebugPath);
- if (mShowDebugPath == Map::MAP_DEBUG)
- _drawDebugPath(graphics);
+ if (mDebugFlags & (Map::MAP_GRID | Map::MAP_COLLISION_TILES))
+ {
+ mMap->drawCollision(graphics, (int) mPixelViewX,
+ (int) mPixelViewY, mDebugFlags);
+ }
+
+ _drawDebugPath(graphics);
}
}
@@ -207,12 +224,15 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
}
// Draw player names, speech, and emotion sprite as needed
- const Beings &beings = beingManager->getAll();
- for (Beings::const_iterator i = beings.begin(), i_end = beings.end();
- i != i_end; ++i)
+ const ActorSprites &actors = actorSpriteManager->getAll();
+ for (ActorSpritesConstIterator it = actors.begin(), it_end = actors.end();
+ it != it_end; it++)
{
- (*i)->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
- (*i)->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY);
+ if ((*it)->getType() == ActorSprite::FLOOR_ITEM)
+ continue;
+
+ Being *b = static_cast<Being*>(*it);
+ b->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
}
if (miniStatusWindow)
@@ -222,6 +242,24 @@ void Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
+void Viewport::shakeScreen(int intensity)
+{
+ float direction = rand()%628 / 100.0f; // random value between 0 and 2PI
+ float x = std::sin(direction) * intensity;
+ float y = std::cos(direction) * intensity;
+ shakeScreen(x, y);
+}
+
+void Viewport::shakeScreen(float x, float y, float decay, unsigned duration)
+{
+ ShakeEffect effect;
+ effect.x = x;
+ effect.y = y;
+ effect.decay = decay;
+ effect.duration = duration;
+ mShakeEffects.push_back(effect);
+}
+
void Viewport::logic()
{
WindowContainer::logic();
@@ -256,47 +294,98 @@ void Viewport::_followMouse()
void Viewport::_drawDebugPath(Graphics *graphics)
{
- // Get the current mouse position
- SDL_GetMouseState(&mMouseX, &mMouseY);
+ if (mDebugFlags & Map::MAP_MOUSE_PATH)
+ {
+ // Get the current mouse position
+ SDL_GetMouseState(&mMouseX, &mMouseY);
- Path debugPath;
+ // Prepare the walkmask corresponding to the protocol
+ unsigned char walkMask;
+ switch (Net::getNetworkType())
+ {
+ case ServerInfo::TMWATHENA:
+ walkMask = Map::BLOCKMASK_WALL | Map::BLOCKMASK_CHARACTER;
+ break;
+ case ServerInfo::MANASERV:
+ default:
+ walkMask = Map::BLOCKMASK_WALL;
+ break;
+ }
- if (Net::getNetworkType() == ServerInfo::TMWATHENA)
- {
- const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32;
- const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32;
- const Vector &playerPos = player_node->getPosition();
+ static Path debugPath;
+ static Vector lastMouseDestination = Vector(0.0f, 0.0f);
+ Vector mouseDestination(mMouseX + (int) mPixelViewX,
+ mMouseY + (int) mPixelViewY);
- debugPath = mMap->findPath(
- (int) (playerPos.x - 16) / 32,
- (int) (playerPos.y - 32) / 32,
- mouseTileX, mouseTileY, 0xFF);
+ if (mouseDestination.x != lastMouseDestination.x
+ || mouseDestination.y != lastMouseDestination.y)
+ {
+ const Vector &playerPos = player_node->getPosition();
- _drawPath(graphics, debugPath);
+ // Adapt the path finding to the precision requested
+ if (Net::getPlayerHandler()->usePixelPrecision())
+ {
+ debugPath = mMap->findPixelPath((int) playerPos.x,
+ (int) playerPos.y,
+ mouseDestination.x,
+ mouseDestination.y,
+ player_node->getCollisionRadius(),
+ walkMask);
+ }
+ else
+ {
+ debugPath = mMap->findTilePath((int) playerPos.x,
+ (int) playerPos.y,
+ mouseDestination.x,
+ mouseDestination.y,
+ walkMask);
+ }
+
+ lastMouseDestination = mouseDestination;
+ }
+
+ _drawPath(graphics, debugPath, gcn::Color(128, 0, 128, 150));
}
- else if (Net::getNetworkType() == ServerInfo::MANASERV)
+
+ // Draw the path debug information for every beings.
+ ActorSpritesConstIterator it, it_end;
+ const ActorSprites &actors = actorSpriteManager->getAll();
+ for (it = actors.begin(), it_end = actors.end() ; it != it_end; it++)
{
- const Vector &playerPos = player_node->getPosition();
- const int playerRadius = player_node->getCollisionRadius();
- // Draw player collision rectangle
- graphics->setColor(gcn::Color(128, 128, 0, 120));
- graphics->fillRectangle(
- gcn::Rectangle((int) playerPos.x - (int) mPixelViewX - playerRadius,
- (int) playerPos.y - (int) mPixelViewY - playerRadius,
- playerRadius * 2, playerRadius * 2));
-
- debugPath = mMap->findPixelPath(
- (int) playerPos.x,
- (int) playerPos.y,
- mMouseX + (int) mPixelViewX,
- mMouseY + (int) mPixelViewY,
- playerRadius, 0xFF);
-
- // We draw the path proposed by mouse
- _drawPath(graphics, debugPath, gcn::Color(128, 0, 128));
-
- // But also the one currently walked on.
- _drawPath(graphics, player_node->getPath(), gcn::Color(0, 0, 255));
+ Being *being = dynamic_cast<Being*>(*it);
+ if (!being)
+ continue;
+
+ const Vector &beingPos = being->getPosition();
+ graphics->setColor(gcn::Color(128, 128, 0, 150));
+
+ if (mDebugFlags & Map::MAP_BEING_COLLISION_RADIUS)
+ {
+ const int radius = being->getCollisionRadius();
+ graphics->fillRectangle(gcn::Rectangle(
+ (int) beingPos.x
+ - (int) mPixelViewX - radius,
+ (int) beingPos.y - (int) mPixelViewY
+ - radius,
+ radius * 2, radius * 2));
+ }
+
+ if (mDebugFlags & Map::MAP_BEING_PATH)
+ _drawPath(graphics, being->getPath(), gcn::Color(0, 0, 255, 150));
+
+ if (mDebugFlags & Map::MAP_BEING_POSITION)
+ {
+ // Draw the absolute x, y position using a cross.
+ graphics->setColor(gcn::Color(0, 0, 255, 255));
+ graphics->drawLine((int) beingPos.x - (int) mPixelViewX - 4,
+ (int) beingPos.y - (int) mPixelViewY - 4,
+ (int) beingPos.x - (int) mPixelViewX + 4,
+ (int) beingPos.y - (int) mPixelViewY + 4);
+ graphics->drawLine((int) beingPos.x - (int) mPixelViewX + 4,
+ (int) beingPos.y - (int) mPixelViewY - 4,
+ (int) beingPos.x - (int) mPixelViewX - 4,
+ (int) beingPos.y - (int) mPixelViewY + 4);
+ }
}
}
@@ -305,33 +394,17 @@ void Viewport::_drawPath(Graphics *graphics, const Path &path,
{
graphics->setColor(color);
- if (Net::getNetworkType() == ServerInfo::TMWATHENA)
+ for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
{
- for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
- {
- int squareX = i->x * 32 - (int) mPixelViewX + 12;
- int squareY = i->y * 32 - (int) mPixelViewY + 12;
-
- graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
- graphics->drawText(
- toString(mMap->getMetaTile(i->x, i->y)->Gcost),
- squareX + 4, squareY + 12, gcn::Graphics::CENTER);
- }
- }
- else if (Net::getNetworkType() == ServerInfo::MANASERV)
- {
- for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
- {
- int squareX = i->x - (int) mPixelViewX;
- int squareY = i->y - (int) mPixelViewY;
-
- graphics->fillRectangle(gcn::Rectangle(squareX - 4, squareY - 4,
- 8, 8));
- graphics->drawText(
- toString(mMap->getMetaTile(i->x / 32, i->y / 32)->Gcost),
- squareX + 4, squareY + 12, gcn::Graphics::CENTER);
- }
-
+ int squareX = i->x - (int) mPixelViewX;
+ int squareY = i->y - (int) mPixelViewY;
+
+ graphics->fillRectangle(gcn::Rectangle(squareX - 4, squareY - 4,
+ 8, 8));
+ graphics->drawText(
+ toString(mMap->getMetaTile(i->x / mMap->getTileWidth(),
+ i->y / mMap->getTileHeight())->Gcost),
+ squareX + 4, squareY + 12, gcn::Graphics::CENTER);
}
}
@@ -345,7 +418,7 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
return;
// Check if we are busy
- if (NPC::isTalking())
+ if (PlayerInfo::isTalking())
return;
mPlayerFollowMouse = false;
@@ -354,9 +427,8 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
const int pixelX = event.getX() + (int) mPixelViewX;
const int pixelY = event.getY() + (int) mPixelViewY;
- mHoverBeing = beingManager->findBeingByPixel(pixelX, pixelY);
- mHoverItem = floorItemManager->
- findByCoordinates(pixelX / mMap->getTileWidth(),
+ mHoverBeing = actorSpriteManager->findBeingByPixel(pixelX, pixelY);
+ mHoverItem = actorSpriteManager->findItem(pixelX / mMap->getTileWidth(),
pixelY / mMap->getTileHeight());
updateCursorType();
@@ -389,33 +461,20 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
// Interact with some being
if (mHoverBeing)
{
- switch (mHoverBeing->getType())
+ if (mHoverBeing->canTalk())
+ mHoverBeing->talkTo();
+ else
{
- // Talk to NPCs
- case Being::NPC:
- static_cast<NPC*>(mHoverBeing)->talk();
- break;
-
- // Attack or walk to monsters or players
- case Being::MONSTER:
- case Being::PLAYER:
- // Ignore it if its dead
- if (!mHoverBeing->isAlive())
- break;
-
+ // Ignore it if its dead
+ if (mHoverBeing->isAlive())
+ {
if (player_node->withinAttackRange(mHoverBeing) ||
keyboard.isKeyActive(keyboard.KEY_ATTACK))
- {
player_node->attack(mHoverBeing,
!keyboard.isKeyActive(keyboard.KEY_TARGET));
- }
else
- {
player_node->setGotoTarget(mHoverBeing);
- }
- break;
- default:
- break;
+ }
}
// Picks up a item if we clicked on one
}
@@ -440,8 +499,8 @@ void Viewport::mousePressed(gcn::MouseEvent &event)
else if (event.getButton() == gcn::MouseEvent::MIDDLE)
{
// Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(
- pixelX, pixelY, 20, Being::MONSTER);
+ Being *target = actorSpriteManager->findNearestLivingBeing(
+ pixelX, pixelY, 20, ActorSprite::MONSTER);
if (target)
player_node->setTarget(target);
@@ -455,25 +514,12 @@ void Viewport::mouseDragged(gcn::MouseEvent &event)
if (mPlayerFollowMouse && !event.isShiftPressed())
{
- if (Net::getNetworkType() == ServerInfo::MANASERV)
- {
- if (get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
- {
- mLocalWalkTime = tick_time;
- player_node->setDestination(event.getX() + (int) mPixelViewX,
- event.getY() + (int) mPixelViewY);
- player_node->pathSetByMouse();
- }
- }
- else
+ if (get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
{
- if (mLocalWalkTime != player_node->getWalkTime())
- {
- mLocalWalkTime = player_node->getWalkTime();
- int destX = (event.getX() + mPixelViewX) / mMap->getTileWidth();
- int destY = (event.getY() + mPixelViewY) / mMap->getTileHeight();
- player_node->setDestination(destX, destY);
- }
+ mLocalWalkTime = tick_time;
+ player_node->setDestination(event.getX() + (int) mPixelViewX,
+ event.getY() + (int) mPixelViewY);
+ player_node->pathSetByMouse();
}
}
}
@@ -481,9 +527,6 @@ void Viewport::mouseDragged(gcn::MouseEvent &event)
void Viewport::mouseReleased(gcn::MouseEvent &event)
{
mPlayerFollowMouse = false;
-
- // Only useful for eAthena but doesn't hurt under ManaServ
- mLocalWalkTime = -1;
}
void Viewport::showPopup(Window *parent, int x, int y, Item *item,
@@ -497,12 +540,6 @@ void Viewport::closePopupMenu()
mPopupMenu->handleLink("cancel");
}
-void Viewport::optionChanged(const std::string &name)
-{
- mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
- mScrollRadius = (int) config.getValue("ScrollRadius", 32);
-}
-
void Viewport::mouseMoved(gcn::MouseEvent &event)
{
// Check if we are on the map
@@ -512,15 +549,11 @@ void Viewport::mouseMoved(gcn::MouseEvent &event)
const int x = (event.getX() + (int) mPixelViewX);
const int y = (event.getY() + (int) mPixelViewY);
- mHoverBeing = beingManager->findBeingByPixel(x, y);
- if (mHoverBeing && mHoverBeing->getType() == Being::PLAYER)
- mBeingPopup->show(getMouseX(), getMouseY(),
- static_cast<Player*>(mHoverBeing));
- else
- mBeingPopup->setVisible(false);
+ mHoverBeing = actorSpriteManager->findBeingByPixel(x, y);
+ mBeingPopup->show(getMouseX(), getMouseY(), mHoverBeing);
- mHoverItem = floorItemManager->findByCoordinates(x / mMap->getTileWidth(),
- y / mMap->getTileHeight());
+ mHoverItem = actorSpriteManager->findItem(x / mMap->getTileWidth(),
+ y / mMap->getTileHeight());
updateCursorType();
}
@@ -532,12 +565,12 @@ void Viewport::updateCursorType()
switch (mHoverBeing->getType())
{
// NPCs
- case Being::NPC:
+ case ActorSprite::NPC:
gui->setCursorType(Gui::CURSOR_TALK);
break;
// Monsters
- case Being::MONSTER:
+ case ActorSprite::MONSTER:
gui->setCursorType(Gui::CURSOR_FIGHT);
break;
default:
@@ -556,15 +589,11 @@ void Viewport::updateCursorType()
}
}
-void Viewport::toggleDebugPath()
+void Viewport::setShowDebugPath(int debugFlags)
{
- mShowDebugPath++;
- if (mShowDebugPath > Map::MAP_SPECIAL)
- mShowDebugPath = Map::MAP_NORMAL;
+ mDebugFlags = debugFlags;
if (mMap)
- {
- mMap->setDebugFlags(mShowDebugPath);
- }
+ mMap->setDebugFlags(debugFlags);
}
void Viewport::hideBeingPopup()
@@ -572,8 +601,27 @@ void Viewport::hideBeingPopup()
mBeingPopup->setVisible(false);
}
-void Viewport::clearHoverBeing(Being *being)
+void Viewport::event(Event::Channel channel, const Event &event)
{
- if (mHoverBeing == being)
- mHoverBeing = 0;
+ if (channel == Event::ActorSpriteChannel
+ && event.getType() == Event::Destroyed)
+ {
+ ActorSprite *actor = event.getActor("source");
+
+ if (mHoverBeing == actor)
+ mHoverBeing = 0;
+
+ if (mHoverItem == actor)
+ mHoverItem = 0;
+ }
+ else if (channel == Event::ConfigChannel &&
+ event.getType() == Event::ConfigOptionChanged)
+ {
+ const std::string option = event.getString("option");
+ if (option == "ScrollLaziness" || option == "ScrollRadius")
+ {
+ mScrollLaziness = config.getIntValue("ScrollLaziness");
+ mScrollRadius = config.getIntValue("ScrollRadius");
+ }
+ }
}