Final AI tweaks.
[NALCG.git] / src / view / view.cpp
blobfefce58d9d3a4700767ea61da62f055ee04045f9
1 #include "view.h"
3 #include "viewframelistener.h"
4 #include "viewconstants.h"
5 #include "../middleman.h"
6 #include "animationfactory.h"
7 #include "bleedinganimation.h"
8 #include "../logic/chessboard.h"
10 View::~View()
12 if( mInputManager )
14 mInputManager->destroyInputObject( mMouse );
15 mInputManager->destroyInputObject( mKeyboard );
16 OIS::InputManager::destroyInputSystem(mInputManager);
17 mInputManager = 0;
20 delete mSystem;
21 mSystem = 0;
22 delete mRenderer;
23 mRenderer = 0;
25 delete mListener;
26 mListener = 0;
27 delete mRoot;
28 mRoot = 0;
31 void View::createRoot()
33 #if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32
34 mRoot = new Root("plugins-windows.cfg");
35 #else
36 mRoot = new Root("plugins-linux.cfg");
37 #endif
40 void View::defineResources()
42 String secName, typeName, archName;
43 ConfigFile cf;
44 cf.load("resources.cfg");
45 ConfigFile::SectionIterator seci = cf.getSectionIterator();
46 while (seci.hasMoreElements())
48 secName = seci.peekNextKey();
49 ConfigFile::SettingsMultiMap *settings = seci.getNext();
50 ConfigFile::SettingsMultiMap::iterator i;
51 for (i = settings->begin(); i != settings->end(); ++i)
53 typeName = i->first;
54 archName = i->second;
55 ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
60 void View::setupRenderSystem()
62 if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())
63 throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");
66 void View::createRenderWindow()
68 mRoot->initialise(true, "NALCG");
71 void View::initializeResourceGroups()
73 TextureManager::getSingleton().setDefaultNumMipmaps(5);
74 ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
77 void View::setupScene()
79 mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");
80 createCamera();
81 mWindow = mRoot->getAutoCreatedWindow();
82 createViewports();
85 void View::setupInputSystem()
87 size_t windowHnd = 0;
88 std::ostringstream windowHndStr;
89 OIS::ParamList pl;
91 mWindow->getCustomAttribute("WINDOW", &windowHnd);
92 windowHndStr << windowHnd;
93 pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
94 if (!mWindow->isFullScreen())
96 pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
97 pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
99 pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
100 pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
102 pl.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
104 mInputManager = OIS::InputManager::createInputSystem(pl);
108 mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
109 mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
111 catch (const OIS::Exception &e)
113 throw Exception(42, e.eText, "Application::setupInputSystem");
115 const OIS::MouseState &ms = mMouse->getMouseState();
116 ms.width = mWindow->getWidth();
117 ms.height = mWindow->getHeight();
120 void View::setupCEGUI()
122 mRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr);
123 mSystem = new CEGUI::System(mRenderer);
125 CEGUI::SchemeManager::getSingleton().loadScheme("TaharezLookSkin.scheme");
127 mSystem->setDefaultMouseCursor("TaharezLook", "MouseArrow");
128 mSystem->setDefaultFont("BlueHighway-12");
130 CEGUI::MouseCursor::getSingleton().setImage(CEGUI::System::getSingleton().getDefaultMouseCursor());
131 mSystem->setMultiClickTimeout(std::numeric_limits<double>::min());
132 CEGUI::MouseCursor::getSingleton().setVisible(false);
135 void View::createFrameListener()
137 mListener = new ViewFrameListener(mKeyboard, mMouse, mWindow, mCamera, mSceneMgr, this);
138 mRoot->addFrameListener(mListener);
141 WindowEventUtilities::addWindowEventListener(mWindow, this);
144 void View::startRenderLoop()
146 mRoot->startRendering();
149 //Unattach OIS before window shutdown (very important under Linux)
150 void View::windowClosed(RenderWindow* rw)
152 //Only close for window that created OIS (the main window in these demos)
153 if( rw == mWindow )
155 if( mInputManager )
157 mInputManager->destroyInputObject( mMouse );
158 mInputManager->destroyInputObject( mKeyboard );
159 OIS::InputManager::destroyInputSystem(mInputManager);
160 mInputManager = 0;
161 mListener->quit(CEGUI::EventArgs());
166 void View::createCamera()
168 mCamera = mSceneMgr->createCamera("PlayerCam");
170 mCamera->setPosition(ViewConstants::WHITE_CAMERA_POSITION * 10);
171 mCamera->lookAt(Vector3::ZERO);
172 mCamera->setNearClipDistance(5);
175 void View::createViewports()
177 // Create one viewport, entire window
178 Viewport* vp = mWindow->addViewport(mCamera);
179 vp->setBackgroundColour(ColourValue(0,0,0));
180 // Alter the camera aspect ratio to match the viewport
181 mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
184 Entity* View::loadEntity(const std::string& entityName, const std::string& modelName)
186 Entity* ent;
187 if (mSceneMgr->hasEntity(entityName))
189 ent = mSceneMgr->getEntity(entityName);
191 else
193 ent = mSceneMgr->createEntity(entityName, modelName);
196 ent->setQueryFlags(0);
198 AnimationStateSet* animations = ent->getAllAnimationStates();
199 if (animations)
201 AnimationStateIterator it = animations->getAnimationStateIterator();
202 while (it.hasMoreElements())
204 AnimationState* animationState = it.getNext();
205 animationState->setEnabled(true);
206 animationState->setLoop(true);
207 animationState->setTimePosition(0);
210 return ent;
213 SceneNode* View::createPiece(char type, const std::string& modelName,
214 const Vector3& location, SceneNode* parent)
216 if (!parent)
218 parent = mSceneMgr->getRootSceneNode();
221 std::ostringstream entityName;
222 entityName << type << modelName << location.x << location.y << location.z << parent->getName() << GenericAnimation::nextName();
224 SceneNode* node = parent->createChildSceneNode(entityName.str(), location);
226 Entity* ent;
227 if (mSceneMgr->hasEntity(entityName.str()))
229 ent = mSceneMgr->getEntity(entityName.str());
231 else
233 ent = mSceneMgr->createEntity(entityName.str(), modelName + ".mesh");
235 //ent->setCastShadows(true);
236 ent->setQueryFlags(0);
237 node->attachObject(ent);
239 if (type == 'P' || type == 'R')
241 node->attachObject(loadEntity(entityName.str() + "l", modelName + "_left_leg.mesh"));
242 node->attachObject(loadEntity(entityName.str() + "r", modelName + "_right_leg.mesh"));
243 if (type == 'R')
245 node->attachObject(loadEntity(entityName.str() + "a", modelName + "_right_arm.mesh"));
246 node->attachObject(loadEntity(entityName.str() + "wb", modelName + "_weapon_base.mesh"));
247 node->attachObject(loadEntity(entityName.str() + "w", modelName + "_weapon.mesh"));
251 // Make white models face the opposite direction.
252 if (modelName.find("white") == 0)
254 node->yaw(Degree(180));
256 node->setInitialState();
257 return node;
260 CEGUI::Window* View::createGUIComponent(const std::string& text, double x, double y,
261 double sizeX, double sizeY, const std::string& type, bool setText, bool visible)
263 CEGUI::WindowManager* win = CEGUI::WindowManager::getSingletonPtr();
264 CEGUI::Window* sheet = win->getWindow("View/Sheet");
266 CEGUI::Window* button = win->createWindow("TaharezLook/" + type, "View/" + text + type);
267 if (setText)
269 button->setText(text);
271 button->setPosition(CEGUI::UVector2(CEGUI::UDim(x, 0), CEGUI::UDim(y, 0)));
272 button->setSize(CEGUI::UVector2(CEGUI::UDim(sizeX, 0), CEGUI::UDim(sizeY, 0)));
274 sheet->addChildWindow(button);
275 button->setVisible(visible);
276 return button;
279 void View::createGUI()
281 CEGUI::WindowManager* win = CEGUI::WindowManager::getSingletonPtr();
282 CEGUI::Window* sheet = win->createWindow("DefaultGUISheet", "View/Sheet");
283 mSystem->setGUISheet(sheet);
285 createGUIComponent("Animation speed", 0.0, 0.165, 0.19, 0.05, "StaticText", false, false)
286 ->setText("Animation speed: 1x");
288 CEGUI::Scrollbar* animationSpeedSlider = static_cast<CEGUI::Scrollbar*>(
289 createGUIComponent("Animation speed", 0.0, 0.215, 0.19, 0.02, "HorizontalScrollbar", false, false));
290 animationSpeedSlider->setDocumentSize(4);
291 animationSpeedSlider->setScrollPosition(1);
292 animationSpeedSlider->subscribeEvent(
293 CEGUI::Scrollbar::EventScrollPositionChanged,
294 CEGUI::Event::Subscriber(&ViewFrameListener::handleAnimationSpeedChanged, mListener));
296 createGUIComponent("Undo", 0.875, 0.45, 0.12, 0.04)->subscribeEvent(CEGUI::PushButton::EventClicked,
297 CEGUI::Event::Subscriber(&View::undo, this));
299 createGUIComponent("Restart", 0.875, 0.505, 0.12, 0.04)->subscribeEvent(CEGUI::PushButton::EventClicked,
300 CEGUI::Event::Subscriber(&View::restart, this));
302 createGUIComponent("Quit", 0.875, 0.55, 0.12, 0.04)->subscribeEvent(CEGUI::PushButton::EventClicked,
303 CEGUI::Event::Subscriber(&ViewFrameListener::quit, mListener));
305 createGUIComponent("FPS info", 0.875, 0.6, 0.12, 0.04, "Button", true,
306 false)->subscribeEvent(CEGUI::PushButton::EventClicked,
307 CEGUI::Event::Subscriber(&ViewFrameListener::toggleDebugInfo, mListener));
309 createGUIComponent("Game log", 0.875, 0.005, 0.12, 0.05, "StaticText");
310 createGUIComponent("Log", 0.875, 0.05, 0.12, 0.4, "Listbox")
311 ->subscribeEvent(CEGUI::Listbox::EventSelectionChanged,
312 CEGUI::Event::Subscriber(&View::visitSelectedLog, this));
314 CEGUI::Window* chooseButton = createGUIComponent("Choose queen", 0.4, 0.30, 0.2, 0.1);
315 chooseButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&View::chooseQueen, this));
316 chooseButton->setVisible(false);
318 chooseButton = createGUIComponent("Choose rook", 0.4, 0.40, 0.2, 0.1);
319 chooseButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&View::chooseRook, this));
320 chooseButton->setVisible(false);
322 chooseButton = createGUIComponent("Choose knight", 0.4, 0.50, 0.2, 0.1);
323 chooseButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&View::chooseKnight, this));
324 chooseButton->setVisible(false);
326 chooseButton = createGUIComponent("Choose bishop", 0.4, 0.60, 0.2, 0.1);
327 chooseButton->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&View::chooseBishop, this));
328 chooseButton->setVisible(false);
330 createGUIComponent("Move assistance level", 0.00, 0.09, 0.18, 0.05, "StaticText", true, false);
332 CEGUI::Spinner* moveAssistanceSpinner = static_cast<CEGUI::Spinner*>(
333 createGUIComponent("Move assistance", 0.18, 0.09, 0.05, 0.05, "Spinner", false, false));
334 moveAssistanceSpinner->setCurrentValue(3.0);
335 moveAssistanceSpinner->setMinimumValue(0.0);
336 moveAssistanceSpinner->setMaximumValue(3.0);
337 moveAssistanceSpinner->subscribeEvent(
338 CEGUI::Spinner::EventValueChanged,
339 CEGUI::Event::Subscriber(&BufferedInputHandler::handleMoveAssistanceChanged,
340 mListener->getHandler()));
342 CEGUI::Window* unsafe = createGUIComponent("Unsafe mode", 0.25, 0.045, 0.3, 0.04, "Checkbox", true, false);
343 unsafe->setText("Allow concurrent animations (UNSAFE!)");
344 unsafe->subscribeEvent(CEGUI::Checkbox::EventCheckStateChanged,
345 CEGUI::Event::Subscriber(&BufferedInputHandler::handleSafeModeChanged, mListener->getHandler()));
347 createGUIComponent(ViewConstants::SHOW_ADDITIONAL, 0.005, 0.005, 0.22, 0.05)->subscribeEvent(CEGUI::PushButton::EventClicked,
348 CEGUI::Event::Subscriber(&ViewFrameListener::hideGUI, mListener));
350 // White dropdown menus
351 createGUIComponent("White:", 0.25, 0.0, 0.15, 0.04, "StaticText", true, true);
353 CEGUI::Combobox* white = static_cast<CEGUI::Combobox*>(createGUIComponent(
354 "White", 0.25, 0.045, 0.15, 0.2, "Combobox", false, true));
355 white->setReadOnly(true);
356 white->setText("Human");
357 white->subscribeEvent(CEGUI::Combobox::EventListSelectionAccepted,
358 CEGUI::Event::Subscriber(&View::updateControllers, this));
360 // White depth spinner
361 CEGUI::Spinner* whiteDepthSpinner = static_cast<CEGUI::Spinner*>(
362 createGUIComponent("White depth", 0.4, 0.00, 0.05, 0.08, "Spinner", false, true));
363 whiteDepthSpinner->setCurrentValue(4.0);
364 whiteDepthSpinner->setMinimumValue(3.0);
365 whiteDepthSpinner->setMaximumValue(6.0);
366 whiteDepthSpinner->subscribeEvent(
367 CEGUI::Spinner::EventValueChanged,
368 CEGUI::Event::Subscriber(&View::handleDepthChanged, this));
370 // Swap sides button
371 createGUIComponent("<=>", 0.475, 0.02, 0.04, 0.05)->subscribeEvent(CEGUI::PushButton::EventClicked,
372 CEGUI::Event::Subscriber(&View::swapPlayers, this));
374 // Black dropdown menus
375 createGUIComponent("Black:", 0.54, 0.0, 0.15, 0.04, "StaticText", true, true);
377 CEGUI::Combobox* black = static_cast<CEGUI::Combobox*>(createGUIComponent(
378 "Black", 0.54, 0.045, 0.15, 0.2, "Combobox", false, true));
379 black->setReadOnly(true);
380 black->setText("Human");
381 black->subscribeEvent(CEGUI::Combobox::EventListSelectionAccepted,
382 CEGUI::Event::Subscriber(&View::updateControllers, this));
384 // Black depth spinner
385 CEGUI::Spinner* blackDepthSpinner = static_cast<CEGUI::Spinner*>(
386 createGUIComponent("Black depth", 0.69, 0.00, 0.05, 0.08, "Spinner", false, true));
387 blackDepthSpinner->setCurrentValue(4.0);
388 blackDepthSpinner->setMinimumValue(3.0);
389 blackDepthSpinner->setMaximumValue(6.0);
390 blackDepthSpinner->subscribeEvent(
391 CEGUI::Spinner::EventValueChanged,
392 CEGUI::Event::Subscriber(&View::handleDepthChanged, this));
394 createGUIComponent("Connect", 0.0, 0.25, 0.1, 0.04, "Button", true, false)
395 ->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&View::connect, this));
397 updateUsers(std::vector<std::string>());
401 void View::recreateLog()
403 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
404 CEGUI::Window* logWindow = wmgr.getWindow("View/LogListbox");
405 CEGUI::Listbox* logList = static_cast<CEGUI::Listbox*>(logWindow);
406 logList->resetList();
408 const std::vector<std::string>& gameLog = mMiddleman->getGameLog();
410 for (std::size_t i = 0; i < gameLog.size(); i++)
412 std::ostringstream text;
413 text << (i + 1) << ". " << gameLog.at(i);
414 CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem(text.str());
415 logList->addItem(item);
417 logList->ensureItemIsVisible(logList->getItemCount() - 1);
420 void View::recreateDeadPieces()
422 // TODO: Check why this crashes on undo during an animation.
423 const Board* board = mMiddleman->getGameStateAt(mMiddleman->getGameLog().size());
424 const std::vector<Piece*> deadPieces = board->getDeadPieces();
425 SceneNode* whiteDeads = mSceneMgr->getSceneNode("White dead pieces");
426 SceneNode* blackDeads = mSceneMgr->getSceneNode("Black dead pieces");
427 blackDeads->removeAndDestroyAllChildren();
428 whiteDeads->removeAndDestroyAllChildren();
430 for (std::vector<Piece*>::const_iterator it = deadPieces.begin();
431 it != deadPieces.end(); it++)
433 char symbol = (*it)->getSymbol();
434 char upperCaseSymbol = symbol & (~(1 << 5));
435 SceneNode* parent = (*it)->getColour() == BLACK ? blackDeads : whiteDeads;
437 int nChildren = parent->numChildren();
438 int xPosition, yPosition;
439 if (nChildren > 3)
441 xPosition = (nChildren + 1) % 3;
442 yPosition = (nChildren + 1) / 3;
444 else
446 xPosition = nChildren % 2;
447 yPosition = nChildren / 2;
449 createPiece(upperCaseSymbol, getMeshName(symbol),
450 convertPosition(xPosition, yPosition * 1.5), parent)->pitch(Degree(-90));
454 void View::createScene()
456 Light *light;
458 mSceneMgr->setAmbientLight(ViewConstants::AMBIENT_COLOUR);
459 //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);
461 light = mSceneMgr->createLight("Yellow");
462 light->setType(Light::LT_POINT);
463 light->setPosition(Vector3(1500, -25000, 1500));
464 light->setDiffuseColour(ViewConstants::YELLOW_COLOUR);
465 light->setSpecularColour(1.0, 1.0, 1.0);
467 light = mSceneMgr->createLight("Blue");
468 light->setType(Light::LT_POINT);
469 light->setPosition(Vector3(-1500, 1500, -1500));
470 light->setDiffuseColour(ViewConstants::BLUE_COLOUR);
471 light->setSpecularColour(1.0, 1.0, 1.0);
473 // Loading the sky material so it doesn't have to be loaded while
474 // playing the opening animation sequence.
475 mSceneMgr->setSkyDome(true, "Sky");
476 mSceneMgr->setSkyDome(false, "Sky");
478 mSceneMgr->createParticleSystem("Selection", "Effects/Selection");
482 void View::createInitialExplosion()
484 SceneNode* explosion = mSceneMgr->getRootSceneNode()->createChildSceneNode(
485 "Initial explosion", Vector3(0, 0, 0));
486 BleedingAnimation* anim = AnimationFactory::createBleedingAnimation(
487 explosion, mSceneMgr, 0, 1.8, "Effects/Explosion");
488 mListener->getAnimationManager().addAnimation(anim);
492 void View::createGround(bool visible)
494 SceneNode* ground = mSceneMgr->getRootSceneNode()->createChildSceneNode("ground", Vector3(0, -50, 0));
495 SceneNode* water = ground->createChildSceneNode("water");
497 Entity* ent = mSceneMgr->createEntity("ground", "ground.mesh");
498 ent->setQueryFlags(0);
499 ground->attachObject(ent);
501 ent = mSceneMgr->createEntity("water", "water.mesh");
502 ent->setQueryFlags(0);
503 water->attachObject(ent);
505 ground->setVisible(visible);
508 void View::createBoard(const Board* board)
510 mBoardWidth = board->getWidth();
511 mBoardHeight = board->getHeight();
513 using ViewConstants::SQUARE_SIDE_LENGTH;
515 for (int i = 0; i < 8; i++)
517 for (int j = 0; j < 8; j++)
519 char symbol = board->getSymbolAt(i, j);
520 if (symbol)
522 char upperCaseSymbol = symbol & (~(1 << 5));
523 createPiece(upperCaseSymbol, getMeshName(symbol), convertPosition(i, j));
528 for (int j = 0; j < int(mBoardHeight); j++)
530 for (int i = 0; i < int(mBoardWidth); i++)
532 std::ostringstream name;
533 name << i << " " << j;
534 Entity* ent = mSceneMgr->createEntity(name.str(), "square.mesh");
536 Vector3 position = convertPosition(i, j);
537 SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(
538 name.str(), position);
539 node->attachObject(ent);
541 if ((i + j) % 2 == 1)
543 ent->setMaterialName("board/square/black");
545 else
547 ent->setMaterialName("board/square/white");
549 ent->setQueryFlags(1 << 0);
551 // Create transparent squares on top of normal squares.
552 // These squares indicate possible movement locations.
553 name << " s";
554 ent = mSceneMgr->createEntity(name.str(), "square.mesh");
555 ent->setMaterialName("board/square/move");
556 ent->setQueryFlags(0);
557 SceneNode* indicatorNode = node->createChildSceneNode(Vector3(0, 1, 0));
558 indicatorNode->attachObject(ent);
559 indicatorNode->scale(1.01, 1.0, 1.01);
560 ent->setVisible(false);
563 SceneNode* invalidMoveNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("InvalidMove");
564 Entity* ent = mSceneMgr->createEntity("InvalidMove", "invalid_move.mesh");
565 ent->setQueryFlags(0);
566 invalidMoveNode->attachObject(ent);
567 invalidMoveNode->setVisible(false);
569 SceneNode* selectionNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("Selection");
570 selectionNode->attachObject(mSceneMgr->getParticleSystem("Selection"));
571 selectionNode->setVisible(false);
573 mSceneMgr->getRootSceneNode()->createChildSceneNode("Black dead pieces",
574 Vector3(ViewConstants::SQUARE_SIDE_LENGTH * 9, -40,
575 ViewConstants::SQUARE_SIDE_LENGTH * 0.5));
576 mSceneMgr->getRootSceneNode()->createChildSceneNode("White dead pieces",
577 Vector3(-ViewConstants::SQUARE_SIDE_LENGTH * 9, -40,
578 ViewConstants::SQUARE_SIDE_LENGTH * 0.5))->yaw(Degree(180));
580 showSelectablePiecesIfInControl();
581 mListener->clearSelectedObject();
584 std::string View::getMeshName(char symbol) const
586 switch (symbol)
588 case 'P': return "black_pawn";
589 case 'R': return "black_rook";
590 case 'N': return "black_knight";
591 case 'B': return "black_bishop";
592 case 'Q': return "black_queen";
593 case 'K': return "black_king";
595 case 'p': return "white_pawn";
596 case 'r': return "white_rook";
597 case 'n': return "white_knight";
598 case 'b': return "white_bishop";
599 case 'q': return "white_queen";
600 case 'k': return "white_king";
601 default:
602 std::ostringstream errorMessage;
603 errorMessage << "getMeshName(): Unknown symbol: " << symbol;
604 errorMessage << " (" << int(symbol) << ")";
605 throw std::runtime_error(errorMessage.str());
609 void View::convertPosition(const Vector3& position, int* x, int* y) const
611 int sideLength = ViewConstants::SQUARE_SIDE_LENGTH;
612 int offsetX = (getBoardWidth() - 1) * sideLength / 2;
613 int offsetY = (getBoardHeight() - 1) * sideLength / 2;
614 // +0.5 for rounding.
615 *x = (position.x + offsetX + 0.5) / sideLength;
616 *y = (position.z + offsetY + 0.5) / sideLength;
619 Vector3 View::convertPosition(double x, double y) const
621 int sideLength = ViewConstants::SQUARE_SIDE_LENGTH;
622 int offsetX = (getBoardWidth() - 1) * sideLength / 2;
623 int offsetY = (getBoardHeight() - 1) * sideLength / 2;
625 return Vector3(x * sideLength - offsetX, 0, y * sideLength - offsetY);
628 bool View::undo(const CEGUI::EventArgs& e)
630 if (mPast)
632 mMiddleman->undo(mMiddleman->getGameLog().size() - mRound);
634 else
636 mMiddleman->undo();
638 ensureLatestState();
639 return true;
642 bool View::restart(const CEGUI::EventArgs& e)
644 ensureLatestState();
645 mMiddleman->undo(mRound);
646 return true;
649 bool View::visitSelectedLog(const CEGUI::EventArgs& e)
651 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
652 CEGUI::Window* logWindow = wmgr.getWindow("View/LogListbox");
653 CEGUI::Listbox* logList = static_cast<CEGUI::Listbox*>(logWindow);
655 CEGUI::ListboxItem* selected = logList->getFirstSelectedItem();
656 if (selected)
659 std::size_t selectedIndex = logList->getItemIndex(selected);
660 if (selectedIndex + 1 != mMiddleman->getGameLog().size())
662 setBoard(mMiddleman->getGameStateAt(selectedIndex + 1), selectedIndex + 1);
664 mSceneMgr->setAmbientLight(ColourValue(0.43, 0.25, 0.07));
665 mSceneMgr->getLight("Yellow")->setDiffuseColour(0.86, 0.5, 0.14);
666 mSceneMgr->getLight("Blue")->setDiffuseColour(0.86, 0.5, 0.14);
668 wmgr.getWindow("View/UndoButton")->setText("Undo future");
669 mPast = true;
671 else
673 ensureLatestState();
675 CEGUI::ListboxItem* newSelected = logList->getListboxItemFromIndex(selectedIndex);
676 if (*newSelected->getText().rbegin() != '<')
678 newSelected->setText(newSelected->getText() + " <");
681 return true;
684 void View::setPromotionMove(int fromX, int fromY, int toX, int toY)
686 // TODO: change to actual move class.
687 promotionMove.clear();
688 promotionMove.push_back(fromX);
689 promotionMove.push_back(fromY);
690 promotionMove.push_back(toX);
691 promotionMove.push_back(toY);
694 bool View::chooseQueen(const CEGUI::EventArgs& e)
696 sendPromotionMove(ChessBoard::PROMOTE_TO_QUEEN);
697 return true;
700 bool View::chooseRook(const CEGUI::EventArgs& e)
702 sendPromotionMove(ChessBoard::PROMOTE_TO_ROOK);
703 return true;
706 bool View::chooseKnight(const CEGUI::EventArgs& e)
708 sendPromotionMove(ChessBoard::PROMOTE_TO_KNIGHT);
709 return true;
712 bool View::chooseBishop(const CEGUI::EventArgs& e)
714 sendPromotionMove(ChessBoard::PROMOTE_TO_BISHOP);
715 return true;
718 void View::sendPromotionMove(unsigned int promoteTo)
720 mMiddleman->move(promotionMove.at(0), promotionMove.at(1),
721 promotionMove.at(2), promotionMove.at(3),
722 promoteTo);
724 setChooseButtonsVisibility(false);
727 void View::setChooseButtonsVisibility(bool visible)
729 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
730 wmgr.getWindow("View/Choose queenButton")->setVisible(visible);
731 wmgr.getWindow("View/Choose rookButton")->setVisible(visible);
732 wmgr.getWindow("View/Choose knightButton")->setVisible(visible);
733 wmgr.getWindow("View/Choose bishopButton")->setVisible(visible);
736 void View::ensureLatestState()
738 if (mPast)
740 mPast = false;
741 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
742 wmgr.getWindow("View/UndoButton")->setText("Undo");
744 std::size_t latestRound = mMiddleman->getGameLog().size();
745 setBoard(mMiddleman->getGameStateAt(latestRound), latestRound);
747 mSceneMgr->setAmbientLight(ViewConstants::AMBIENT_COLOUR);
748 mSceneMgr->getLight("Yellow")->setDiffuseColour(ViewConstants::YELLOW_COLOUR);
749 mSceneMgr->getLight("Blue")->setDiffuseColour(ViewConstants::BLUE_COLOUR);
753 void View::start()
755 try {
756 createRoot();
757 defineResources();
758 setupRenderSystem();
759 createRenderWindow();
760 initializeResourceGroups();
761 setupScene();
762 setupInputSystem();
763 setupCEGUI();
764 createFrameListener();
765 createGUI();
766 createScene();
767 createBoard(mMiddleman->getGameStateAt(0));
768 createGround(false);
769 createInitialExplosion();
770 startRenderLoop();
771 } catch( Exception& e ) {
772 fprintf(stderr, "An exception has occurred: %s\n", e.what());
777 bool View::updateControllers(const CEGUI::EventArgs& e)
779 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
780 CEGUI::Combobox* white = static_cast<CEGUI::Combobox*>(wmgr.getWindow("View/WhiteCombobox"));
781 CEGUI::Combobox* black = static_cast<CEGUI::Combobox*>(wmgr.getWindow("View/BlackCombobox"));
783 std::size_t whiteIndex = white->getItemIndex(white->findItemWithText(white->getText(), 0));
784 std::size_t blackIndex = black->getItemIndex(black->findItemWithText(black->getText(), 0));
786 mMiddleman->setControl(whiteIndex, blackIndex);
788 if (whiteIndex > mMiddleman->getAICount())
790 mMiddleman->sendChallenge(white->getText().c_str());
793 if (blackIndex > mMiddleman->getAICount())
795 mMiddleman->sendChallenge(black->getText().c_str());
798 return true;
801 bool View::swapPlayers(const CEGUI::EventArgs& e)
803 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
804 CEGUI::Window* white = wmgr.getWindow("View/WhiteCombobox");
805 CEGUI::Window* black = wmgr.getWindow("View/BlackCombobox");
807 const CEGUI::String whitePlayer = white->getText();
808 white->setText(black->getText());
809 black->setText(whitePlayer);
811 return updateControllers(e);
814 void View::promptChallenge(const std::string& challengerName)
816 mMiddleman->respondToChallenge(true);
820 void View::updateUsers(const std::vector<std::string>& users)
822 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
823 CEGUI::Combobox* white = static_cast<CEGUI::Combobox*>(wmgr.getWindow("View/WhiteCombobox"));
824 CEGUI::Combobox* black = static_cast<CEGUI::Combobox*>(wmgr.getWindow("View/BlackCombobox"));
826 white->resetList();
827 black->resetList();
828 white->addItem(new CEGUI::ListboxTextItem("Human"));
829 black->addItem(new CEGUI::ListboxTextItem("Human"));
831 for (std::size_t i = 0; i < mMiddleman->getAICount(); i++)
833 std::string name = mMiddleman->getAIInfoAt(i).getName();
834 white->addItem(new CEGUI::ListboxTextItem(name));
835 black->addItem(new CEGUI::ListboxTextItem(name));
838 for (std::size_t i = 0; i < users.size(); i++)
840 const std::string& user = users.at(i);
841 white->addItem(new CEGUI::ListboxTextItem(user));
842 black->addItem(new CEGUI::ListboxTextItem(user));
846 bool View::connect(const CEGUI::EventArgs& e)
848 mMiddleman->connect();
849 return true;
853 bool View::handleDepthChanged(const CEGUI::EventArgs& e)
855 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
856 CEGUI::Spinner* white = static_cast<CEGUI::Spinner*>(wmgr.getWindow("View/White depthSpinner"));
857 CEGUI::Spinner* black = static_cast<CEGUI::Spinner*>(wmgr.getWindow("View/Black depthSpinner"));
859 mMiddleman->setAICutoffDepth(white->getCurrentValue() + 0.5f, black->getCurrentValue() + 0.5f);
861 return true;