00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ministatus.h"
00023 #include "popupmenu.h"
00024 #include "viewport.h"
00025
00026 #include "../beingmanager.h"
00027 #include "../configuration.h"
00028 #include "../flooritemmanager.h"
00029 #include "../game.h"
00030 #include "../graphics.h"
00031 #include "../keyboardconfig.h"
00032 #include "../localplayer.h"
00033 #include "../map.h"
00034 #include "../monster.h"
00035 #include "../npc.h"
00036 #include "../textmanager.h"
00037
00038 #include "../resources/monsterinfo.h"
00039 #include "../resources/resourcemanager.h"
00040
00041 #include "../utils/stringutils.h"
00042
00043 extern volatile int tick_time;
00044
00045 Viewport::Viewport():
00046 mMap(0),
00047 mMouseX(0),
00048 mMouseY(0),
00049 mPixelViewX(0.0f),
00050 mPixelViewY(0.0f),
00051 mTileViewX(0),
00052 mTileViewY(0),
00053 mShowDebugPath(false),
00054 mVisibleNames(false),
00055 mPlayerFollowMouse(false),
00056 #ifdef TMWSERV_SUPPORT
00057 mLocalWalkTime(-1)
00058 #else
00059 mWalkTime(0)
00060 #endif
00061 {
00062 setOpaque(false);
00063 addMouseListener(this);
00064
00065 mScrollLaziness = (int) config.getValue("ScrollLaziness", 16);
00066 mScrollRadius = (int) config.getValue("ScrollRadius", 0);
00067 mScrollCenterOffsetX = (int) config.getValue("ScrollCenterOffsetX", 0);
00068 mScrollCenterOffsetY = (int) config.getValue("ScrollCenterOffsetY", 0);
00069 mVisibleNames = config.getValue("visiblenames", 1);
00070
00071 config.addListener("ScrollLaziness", this);
00072 config.addListener("ScrollRadius", this);
00073 config.addListener("visiblenames", this);
00074
00075 mPopupMenu = new PopupMenu;
00076 }
00077
00078 Viewport::~Viewport()
00079 {
00080 delete mPopupMenu;
00081
00082 config.removeListener("visiblenames", this);
00083 }
00084
00085 void Viewport::setMap(Map *map)
00086 {
00087 mMap = map;
00088 }
00089
00090 extern MiniStatusWindow *miniStatusWindow;
00091
00092 void Viewport::draw(gcn::Graphics *gcnGraphics)
00093 {
00094 static int lastTick = tick_time;
00095
00096 if (!mMap || !player_node)
00097 return;
00098
00099 Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
00100
00101
00102
00103 player_node->mMapInitialized = true;
00104
00105
00106 if (tick_time < lastTick)
00107 {
00108 lastTick = tick_time;
00109 }
00110
00111
00112 #ifdef TMWSERV_SUPPORT
00113 int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2;
00114 int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2;
00115
00116 const Vector &playerPos = player_node->getPosition();
00117 const int player_x = (int) playerPos.x - midTileX;
00118 const int player_y = (int) playerPos.y - midTileY;
00119 #else
00120 int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 32 / 2;
00121 int midTileY = (graphics->getHeight() + mScrollCenterOffsetY) / 32 / 2;
00122
00123 int player_x = (player_node->mX - midTileX) * 32 +
00124 player_node->getXOffset();
00125 int player_y = (player_node->mY - midTileY) * 32 +
00126 player_node->getYOffset();
00127 #endif
00128
00129 if (mScrollLaziness < 1)
00130 mScrollLaziness = 1;
00131
00132
00133 while (lastTick < tick_time)
00134 {
00135 if (player_x > mPixelViewX + mScrollRadius)
00136 {
00137 mPixelViewX += (player_x - mPixelViewX - mScrollRadius) /
00138 mScrollLaziness;
00139 }
00140 if (player_x < mPixelViewX - mScrollRadius)
00141 {
00142 mPixelViewX += (player_x - mPixelViewX + mScrollRadius) /
00143 mScrollLaziness;
00144 }
00145 if (player_y > mPixelViewY + mScrollRadius)
00146 {
00147 mPixelViewY += (player_y - mPixelViewY - mScrollRadius) /
00148 mScrollLaziness;
00149 }
00150 if (player_y < mPixelViewY - mScrollRadius)
00151 {
00152 mPixelViewY += (player_y - mPixelViewY + mScrollRadius) /
00153 mScrollLaziness;
00154 }
00155 lastTick++;
00156 }
00157
00158
00159 if ( player_x - mPixelViewX > graphics->getWidth() / 2
00160 || mPixelViewX - player_x > graphics->getWidth() / 2
00161 || mPixelViewY - player_y > graphics->getHeight() / 2
00162 || player_y - mPixelViewY > graphics->getHeight() / 2
00163 )
00164 {
00165 mPixelViewX = player_x;
00166 mPixelViewY = player_y;
00167 };
00168
00169
00170 const int viewXmax =
00171 mMap->getWidth() * mMap->getTileWidth() - graphics->getWidth();
00172 const int viewYmax =
00173 mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight();
00174 if (mMap)
00175 {
00176 if (mPixelViewX < 0)
00177 mPixelViewX = 0;
00178 if (mPixelViewY < 0)
00179 mPixelViewY = 0;
00180 if (mPixelViewX > viewXmax)
00181 mPixelViewX = viewXmax;
00182 if (mPixelViewY > viewYmax)
00183 mPixelViewY = viewYmax;
00184 }
00185
00186 mTileViewX = (int) (mPixelViewX + 16) / 32;
00187 mTileViewY = (int) (mPixelViewY + 16) / 32;
00188
00189
00190 if (mMap)
00191 {
00192 mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
00193
00194 if (mShowDebugPath) {
00195 mMap->drawCollision(graphics,
00196 (int) mPixelViewX,
00197 (int) mPixelViewY);
00198 #if 0
00199 drawDebugPath(graphics);
00200 #endif
00201 }
00202 }
00203
00204 if (player_node->mUpdateName)
00205 {
00206 player_node->mUpdateName = false;
00207 player_node->setName(player_node->getName());
00208 }
00209
00210
00211 if (textManager)
00212 {
00213 textManager->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
00214 }
00215
00216
00217 const Beings &beings = beingManager->getAll();
00218 for (Beings::const_iterator i = beings.begin(), i_end = beings.end();
00219 i != i_end; ++i)
00220 {
00221 (*i)->drawSpeech((int) mPixelViewX, (int) mPixelViewY);
00222 (*i)->drawEmotion(graphics, (int) mPixelViewX, (int) mPixelViewY);
00223 }
00224
00225 if (miniStatusWindow)
00226 miniStatusWindow->drawIcons(graphics);
00227
00228
00229 WindowContainer::draw(gcnGraphics);
00230 }
00231
00232 void Viewport::logic()
00233 {
00234 WindowContainer::logic();
00235
00236 if (!mMap || !player_node)
00237 return;
00238
00239 Uint8 button = SDL_GetMouseState(&mMouseX, &mMouseY);
00240
00241 if (mPlayerFollowMouse && button & SDL_BUTTON(1) &&
00242 #ifdef TMWSERV_SUPPORT
00243 get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
00244 {
00245 mLocalWalkTime = tick_time;
00246 player_node->setDestination(mMouseX + (int) mPixelViewX,
00247 mMouseY + (int) mPixelViewY);
00248 #else
00249 mWalkTime != player_node->mWalkTime)
00250 {
00251 player_node->setDestination(mMouseX / 32 + mTileViewX,
00252 mMouseY / 32 + mTileViewY);
00253 mWalkTime = player_node->mWalkTime;
00254 #endif
00255 }
00256 }
00257
00258 void Viewport::drawDebugPath(Graphics *graphics)
00259 {
00260
00261 SDL_GetMouseState(&mMouseX, &mMouseY);
00262
00263 const int mouseTileX = (mMouseX + (int) mPixelViewX) / 32;
00264 const int mouseTileY = (mMouseY + (int) mPixelViewY) / 32;
00265 const Vector &playerPos = player_node->getPosition();
00266
00267 Path debugPath = mMap->findPath(
00268 (int) playerPos.x / 32,
00269 (int) playerPos.y / 32,
00270 mouseTileX, mouseTileY, 0xFF);
00271
00272 drawPath(graphics, debugPath);
00273 }
00274
00275 void Viewport::drawPath(Graphics *graphics, const Path &path)
00276 {
00277 graphics->setColor(gcn::Color(255, 0, 0));
00278 for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
00279 {
00280 int squareX = i->x * 32 - (int) mPixelViewX + 12;
00281 int squareY = i->y * 32 - (int) mPixelViewY + 12;
00282
00283 graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
00284 graphics->drawText(
00285 toString(mMap->getMetaTile(i->x, i->y)->Gcost),
00286 squareX + 4, squareY + 12, gcn::Graphics::CENTER);
00287 }
00288 }
00289
00290 void Viewport::mousePressed(gcn::MouseEvent &event)
00291 {
00292
00293 if (!mMap || !player_node || !player_node->isAlive())
00294 return;
00295
00296
00297 if (current_npc)
00298 return;
00299
00300 mPlayerFollowMouse = false;
00301
00302 const int pixelx = event.getX() + (int) mPixelViewX;
00303 const int pixely = event.getY() + (int) mPixelViewY;
00304 const int tilex = pixelx / mMap->getTileWidth();
00305 const int tiley = pixely / mMap->getTileHeight();
00306
00307
00308 if (event.getButton() == gcn::MouseEvent::RIGHT)
00309 {
00310 Being *being;
00311 FloorItem *floorItem;
00312
00313 if ((being = beingManager->findBeingByPixel(pixelx, pixely)) &&
00314 being != player_node)
00315 {
00316 mPopupMenu->showPopup(event.getX(), event.getY(), being);
00317 return;
00318 }
00319 else if ((floorItem = floorItemManager->findByCoordinates(tilex,
00320 tiley)))
00321 {
00322 mPopupMenu->showPopup(event.getX(), event.getY(), floorItem);
00323 return;
00324 }
00325 }
00326
00327
00328 if (mPopupMenu->isVisible())
00329 {
00330 mPopupMenu->setVisible(false);
00331 return;
00332 }
00333
00334
00335 if (event.getButton() == gcn::MouseEvent::LEFT)
00336 {
00337 FloorItem *item;
00338 #ifdef EATHENA_SUPPORT
00339 Being *being;
00340
00341
00342
00343 if ((being = beingManager->findBeingByPixel(pixelx, pixely)))
00344 {
00345 switch (being->getType())
00346 {
00347 case Being::NPC:
00348 dynamic_cast<NPC*>(being)->talk();
00349 break;
00350
00351 case Being::MONSTER:
00352 case Being::PLAYER:
00353 if (being->mAction == Being::DEAD)
00354 break;
00355
00356 if (player_node->withinAttackRange(being) ||
00357 keyboard.isKeyActive(keyboard.KEY_ATTACK))
00358 {
00359 player_node->setGotoTarget(being);
00360 player_node->attack(being,
00361 !keyboard.isKeyActive(keyboard.KEY_TARGET));
00362 }
00363 else
00364 {
00365 player_node->setDestination(tilex, tiley);
00366 }
00367 break;
00368
00369 default:
00370 break;
00371 }
00372 }
00373
00374 else
00375 #endif
00376 if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
00377 {
00378 player_node->pickUp(item);
00379 }
00380 else if (player_node->mAction == Being::SIT)
00381 {
00382 return;
00383 }
00384
00385 else
00386 {
00387 #ifdef TMWSERV_SUPPORT
00388
00389 Uint8 *keys = SDL_GetKeyState(NULL);
00390 if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) &&
00391 get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
00392 {
00393 mLocalWalkTime = tick_time;
00394 player_node->setDestination(event.getX() + (int) mPixelViewX,
00395 event.getY() + (int) mPixelViewY);
00396 }
00397 #else
00398 player_node->stopAttack();
00399 player_node->setDestination(tilex, tiley);
00400 #endif
00401 mPlayerFollowMouse = true;
00402 }
00403 }
00404 else if (event.getButton() == gcn::MouseEvent::MIDDLE)
00405 {
00406
00407 Being *target = beingManager->findNearestLivingBeing(
00408 tilex, tiley,
00409 20, Being::MONSTER);
00410
00411 if (target)
00412 player_node->setTarget(target);
00413 }
00414 }
00415
00416 void Viewport::mouseDragged(gcn::MouseEvent &event)
00417 {
00418 if (!mMap || !player_node)
00419 return;
00420
00421 #ifdef TMWSERV_SUPPORT
00422 if (mPlayerFollowMouse
00423 && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
00424 {
00425 mLocalWalkTime = tick_time;
00426 player_node->setDestination(event.getX() + (int) mPixelViewX,
00427 event.getY() + (int) mPixelViewY);
00428 }
00429 #else
00430 if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime)
00431 {
00432 int destX = event.getX() / 32 + mTileViewX;
00433 int destY = event.getY() / 32 + mTileViewY;
00434 player_node->setDestination(destX, destY);
00435 }
00436 #endif
00437 }
00438
00439 void Viewport::mouseReleased(gcn::MouseEvent &event)
00440 {
00441 mPlayerFollowMouse = false;
00442 }
00443
00444 void Viewport::showPopup(int x, int y, Item *item)
00445 {
00446 mPopupMenu->showPopup(x, y, item);
00447 }
00448
00449 void Viewport::closePopupMenu()
00450 {
00451 mPopupMenu->handleLink("cancel");
00452 }
00453
00454 void Viewport::optionChanged(const std::string &name)
00455 {
00456 mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
00457 mScrollRadius = (int) config.getValue("ScrollRadius", 32);
00458
00459 if (name == "visiblenames") {
00460 mVisibleNames = config.getValue("visiblenames", 1);
00461 }
00462 }
00463
00464 void Viewport::mouseMoved(gcn::MouseEvent &event)
00465 {
00466
00467 if (!mMap || !player_node)
00468 return;
00469
00470 const int tilex = (event.getX() + (int) mPixelViewX) / 32;
00471 const int tiley = (event.getY() + (int) mPixelViewY) / 32;
00472
00473 mSelectedBeing = beingManager->findBeing(tilex, tiley);
00474 }