converse-system-menu.cpp

Go to the documentation of this file.
00001 /*
00002  * converse-system-menu.cpp
00003  *
00004  * Copyright (C) 2008  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of an object that can host system menus.
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "client-converse.h"            // always include our own header first!
00036 #include "application.h"
00037 
00038 #include "datahash/datahash_util.h"
00039 #include "dialog/request.h"
00040 
00041 
00042 namespace aesop {
00043 
00044 
00045 
00046 ////////////////////////////////////////////////////////////////////////////////
00047 //
00048 //      SMHost -- class that implements converse::ConversationHost for
00049 //      System Menus.
00050 //
00051 ////////////////////////////////////////////////////////////////////////////////
00052 
00053 class SMHost : public converse::ConversationHost {
00054 public:
00055         SMHost(void) throw();
00056         ~SMHost(void) throw() { }
00057 
00058         // public class methods ------------------------------------------------
00059         void initialize(IN int playerId,
00060                                 IN Application * app);
00061 
00062         // converse::ConversationHost class interface methods ------------------
00063         int getCurrentDialogIdTS(void);
00064         void handleReplyTS(IN int dialogID,
00065                                 IN const Datahash * reply);
00066         std::string getDialogDataTS(void);
00067         bool updateState(void);
00068 
00069 private:
00070         // private typedefs ----------------------------------------------------
00071         enum eDialog {
00072                 eDialog_Main            = 1,    ///< starting dialog
00073                 eDialog_Search          = 2,    ///< picking servers
00074                 eDialog_NoConnect       = 3,    ///< could not connect
00075 
00076                 // keep this last
00077                 eDialog_Done            = 0     ///< end dialog
00078         };
00079 
00080 
00081         // private helper methods ----------------------------------------------
00082 
00083         // private member data -------------------------------------------------
00084         Application *           m_app;  // weak ref!  Do not delete!
00085         smart_ptr<i18n::Manager> m_i18nMgr;
00086         eDialog                 m_dialog;
00087         int                     m_playerId;
00088 };
00089 
00090 
00091 
00092 SMHost::SMHost(void)
00093 throw()
00094 {
00095         m_dialog = eDialog_Main;
00096         m_playerId = 0;
00097         m_app = NULL;
00098 }
00099 
00100 
00101 
00102 void
00103 SMHost::initialize
00104 (
00105 IN int playerId,
00106 IN Application * app
00107 )
00108 {
00109         ASSERT(playerId > 0, "bad player id: %d", playerId);
00110         ASSERT(app, "null");
00111 
00112         ASSERT(!m_app, "already have application?");
00113         m_app = app;
00114 
00115         ASSERT(!m_playerId, "already have player?");
00116         m_playerId = playerId;
00117 
00118         story::Story * story = app->getStory();
00119         ASSERT(story, "null");
00120 
00121         m_i18nMgr = story->getI18nManager("converse/system.txt");
00122         ASSERT(m_i18nMgr, "failed to create locale manager");
00123 }
00124 
00125 
00126 
00127 ////////////////////////////////////////////////////////////////////////////////
00128 //
00129 //      SMHost -- converse::ConversationHost class interface methods
00130 //
00131 ////////////////////////////////////////////////////////////////////////////////
00132 
00133 int
00134 SMHost::getCurrentDialogIdTS
00135 (
00136 void
00137 )
00138 {
00139         return m_dialog;
00140 }
00141 
00142 
00143 
00144 void
00145 SMHost::handleReplyTS
00146 (
00147 IN int dialogId,
00148 IN const Datahash * reply
00149 )
00150 {
00151         ASSERT(dialogId > 0, "Bad dialog id: %d", dialogId);
00152         ASSERT(reply, "null");
00153 
00154         std::string submit = getString(reply, "submit");
00155         DPRINTF("Received submit='%s'", submit.c_str());
00156 
00157         if ("close" == submit) {
00158                 m_dialog = eDialog_Done;
00159         }
00160         if ("main" == submit) {
00161                 m_dialog = eDialog_Main;
00162         }
00163         if ("search" == submit) {
00164                 m_dialog = eDialog_Search;
00165         }
00166         if ("gamepad" == submit) {
00167                 m_app->configureControls(m_playerId);
00168                 m_dialog = eDialog_Done;
00169         }
00170         if (!strncmp(submit.c_str(), "connect.", 8)) {
00171                 const char * serverKey = submit.c_str() + 8;
00172                 DPRINTF("User selected server '%s'", serverKey);
00173                 if (m_app->requestConnect(serverKey)) {
00174                         m_dialog = eDialog_Done;
00175                 } else {
00176                         m_dialog = eDialog_NoConnect;
00177                 }
00178         }
00179         if ("kb" == submit) {
00180                 m_app->takeKeyboard(m_playerId);
00181                 m_dialog = eDialog_Done;
00182         }
00183         if ("ng" == submit) {
00184                 m_app->newGame(m_playerId);
00185                 m_dialog = eDialog_Done;
00186         }
00187         if ("np" == submit) {
00188                 DPRINTF("Adding player!");
00189                 m_app->addPlayer();
00190         }
00191         if ("qg" == submit) {
00192                 m_app->dropPlayer(m_playerId);
00193                 m_dialog = eDialog_Done;
00194         }
00195 }
00196 
00197 
00198 
00199 
00200 std::string
00201 SMHost::getDialogDataTS
00202 (
00203 void
00204 )
00205 {
00206         ASSERT(m_i18nMgr, "null");
00207         ASSERT(m_app, "null");
00208 
00209         player_stats_t ps;
00210         if (!m_app->getPlayerStats(m_playerId, ps)) {
00211                 // this will happen if a player exits with dialog up
00212                 // DPRINTF("Player id is no longer valid: %d", m_playerId);
00213                 return "";
00214         }
00215 
00216         dialog::ContainerRequest cr;
00217 
00218         if (eDialog_Main == m_dialog) {
00219                 cr.addLabel(i18n::getString(m_i18nMgr, "menuTitle"));
00220                 cr.addLabel("");
00221                 if (eClientState_Searching == ps.clientState) {
00222                         cr.addButton("search", i18n::getString(m_i18nMgr, "search"));
00223                 } else if (eClientState_Connecting == ps.clientState) {
00224                         cr.addLabel(i18n::getString(m_i18nMgr, "connecting"));
00225                 } else if (eClientState_Connected == ps.clientState) {
00226                         cr.addButton("ng", i18n::getString(m_i18nMgr, "newGame"));
00227                 }
00228                 cr.addLabel("");
00229                 cr.addButton("gamepad",
00230                     i18n::getString(m_i18nMgr, "getGamepad"));
00231                 cr.addLabel("");
00232                 cr.addButton("np", i18n::getString(m_i18nMgr, "addPlayer"));
00233                 cr.addLabel("");
00234 
00235                 if (!ps.haveKeyboard) {
00236                         cr.addButton("kb", i18n::getString(m_i18nMgr, "takeKeyboard"));
00237                         cr.addLabel("");
00238                 }
00239 
00240                 dialog::ContainerRequest cr2(dialog::ContainerRequest::eAxis_Horizontal);
00241                 cr2.addButton("qg", i18n::getString(m_i18nMgr, "quitGame"));
00242                 cr2.addButton("close", i18n::getString(m_i18nMgr, "closeMenu"));
00243                 cr.addContainer(cr2);
00244         } else if (eDialog_Search == m_dialog) {
00245                 cr.addLabel(getString(m_i18nMgr, "selectServer"));
00246 
00247                 const server_map_t& servers = m_app->getServers();
00248 
00249                 if (!servers.size()) {
00250                         cr.addLabel("");
00251                         cr.addLabel(getString(m_i18nMgr, "noServers"));
00252                 }
00253 
00254                 // loop through and add all known servers
00255                 server_map_t::iterator_t i;
00256                 std::string key;
00257                 server_info_t si;
00258                 servers.getIterator(i);
00259                 while (servers.getNextElement(i, key, si)) {
00260                 //      DPRINTF("  Adding server to list: %s", si.publicName.c_str());
00261                 //      DPRINTF("    (%s)", key.c_str());
00262                         std::string submit = "connect.";
00263                         submit += key;
00264 
00265                         // construct a sub-container
00266                         dialog::ContainerRequest cr2;
00267                         cr2.addButton(submit.c_str(), si.publicName.c_str());
00268                                 std::string info = "(";
00269                         info += key;
00270                         info += ")";
00271                         cr2.addLabel(info.c_str());
00272 
00273                         // add to overall menu
00274                         cr.addLabel("");
00275                         cr.addContainer(cr2);
00276                 }
00277 
00278                 cr.addLabel("");
00279                 cr.addButton("main", getString(m_i18nMgr, "back"));
00280         } else if (eDialog_NoConnect == m_dialog) {
00281                 cr.addLabel(getString(m_i18nMgr, "noConnect"));
00282                 cr.addLabel("");
00283                 cr.addButton("search", getString(m_i18nMgr, "back"));
00284         } else {
00285         }
00286 
00287         return cr.get();
00288 }
00289 
00290 
00291 
00292 bool
00293 SMHost::updateState
00294 (
00295 void
00296 )
00297 {
00298         if (eDialog_Search != m_dialog)
00299                 return false;   // no change
00300 
00301         // TODO: see if server list actually change?
00302         // for now, always refresh...
00303         return true;
00304 }
00305 
00306 
00307 
00308 ////////////////////////////////////////////////////////////////////////////////
00309 //
00310 //      SMHost -- private helper methods
00311 //
00312 ////////////////////////////////////////////////////////////////////////////////
00313 
00314 
00315 
00316 ////////////////////////////////////////////////////////////////////////////////
00317 //
00318 //      factory methods
00319 //
00320 ////////////////////////////////////////////////////////////////////////////////
00321 
00322 smart_ptr<converse::ConversationHost>
00323 createSystemMenuHost
00324 (
00325 IN int playerId,
00326 IN Application * app
00327 )
00328 {
00329         ASSERT(playerId > 0, "Bad player id: %d", playerId);
00330         ASSERT(app, "null");
00331 
00332         smart_ptr<SMHost> local = new SMHost;
00333         ASSERT(local, "out of memory");
00334 
00335         local->initialize(playerId, app);
00336 
00337         return local;
00338 }
00339 
00340 
00341 
00342 };      // aesop namespace
00343