1 /*
2  *  The ManaPlus Client
3  *  Copyright (C) 2011-2019  The ManaPlus Developers
4  *  Copyright (C) 2019-2021  Andrei Karas
5  *
6  *  This file is part of The ManaPlus Client.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef GUI_WIDGETS_TABS_SOCIALNAVIGATIONTAB_H
23 #define GUI_WIDGETS_TABS_SOCIALNAVIGATIONTAB_H
24 
25 #include "gui/widgets/tabs/socialtab.h"
26 
27 #include "actormanager.h"
28 #include "configuration.h"
29 
30 #include "gui/models/beingslistmodel.h"
31 
32 #include "gui/windows/outfitwindow.h"
33 
34 #include "being/localplayer.h"
35 
36 #include "input/keyboardconfig.h"
37 
38 #include "utils/delete2.h"
39 #include "utils/gettext.h"
40 
41 #include "resources/map/map.h"
42 #include "resources/map/mapitem.h"
43 #include "resources/map/speciallayer.h"
44 
45 #include "localconsts.h"
46 
47 class Avatar;
48 
49 class SocialNavigationTab final : public SocialTab
50 {
51     public:
SocialNavigationTab(const Widget2 * const widget,const Opaque showBackground)52         SocialNavigationTab(const Widget2 *const widget,
53                             const Opaque showBackground) :
54             SocialTab(widget),
55             mBeings(new BeingsListModel)
56         {
57             createControls(mBeings, showBackground);
58 
59             // TRANSLATORS: Navigation tab name in social window.
60             // TRANSLATORS: Should be small
61             setCaption(_("Nav"));
62             mMenuAction = "navigation";
63         }
64 
65         A_DELETE_COPY(SocialNavigationTab)
66 
~SocialNavigationTab()67         ~SocialNavigationTab() override final
68         {
69             delete2(mList)
70             delete2(mScroll)
71             delete2(mBeings)
72         }
73 
updateList()74         void updateList() override final
75         {
76             if ((socialWindow == nullptr) || (localPlayer == nullptr))
77                 return;
78 
79             const Map *const map = socialWindow->getMap();
80             if ((map == nullptr) || map->empty())
81                 return;
82 
83             if (socialWindow->getProcessedPortals())
84                 return;
85 
86             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
87             STD_VECTOR<MapItem*> portals = map->getPortals();
88 
89             STD_VECTOR<MapItem*>::const_iterator i = portals.begin();
90             const SpecialLayer *const specialLayer = map->getSpecialLayer();
91 
92             STD_VECTOR<Avatar*>::iterator ia = avatars->begin();
93 
94             while (ia != avatars->end())
95             {
96                 delete *ia;
97                 ++ ia;
98             }
99 
100             avatars->clear();
101 
102             int online = 0;
103             int total = 0;
104 
105             int idx = 0;
106             while (i != portals.end())
107             {
108                 MapItem *portal = *i;
109                 if (portal == nullptr)
110                     continue;
111 
112                 const int x = portal->getX();
113                 const int y = portal->getY();
114 
115                 const std::string name = strprintf("%s [%d %d]",
116                     portal->getComment().c_str(), x, y);
117 
118                 Avatar *const ava = new Avatar(name);
119                 if (localPlayer != nullptr)
120                     ava->setOnline(localPlayer->isReachable(x, y, true));
121                 else
122                     ava->setOnline(false);
123                 ava->setLevel(-1);
124                 ava->setType(portal->getType());
125                 ava->setX(x);
126                 ava->setY(y);
127                 avatars->push_back(ava);
128 
129                 if (ava->getOnline())
130                     online ++;
131                 total ++;
132 
133                 if (config.getBoolValue("drawHotKeys")
134                     && idx < 80 && (outfitWindow != nullptr))
135                 {
136                     Being *const being = actorManager
137                         ->findPortalByTile(x, y);
138                     if (being != nullptr)
139                     {
140                         being->setName(KeyboardConfig::getKeyShortString(
141                             OutfitWindow::keyName(idx)));
142                     }
143 
144                     if (specialLayer != nullptr)
145                     {
146                         portal = specialLayer->getTile(
147                             ava->getX(), ava->getY());
148                         if (portal != nullptr)
149                         {
150                             portal->setName(KeyboardConfig::getKeyShortString(
151                                 OutfitWindow::keyName(idx)));
152                         }
153                     }
154                 }
155 
156                 ++i;
157                 idx ++;
158             }
159             if (socialWindow != nullptr)
160                 socialWindow->setProcessedPortals(true);
161 
162             // TRANSLATORS: social window label
163             mCounterString = strprintf(_("Portals: %u/%u"),
164                 CAST_U32(online),
165                 CAST_U32(total));
166             updateCounter();
167         }
168 
selectIndex(const unsigned num)169         void selectIndex(const unsigned num) override final
170         {
171             if (localPlayer == nullptr)
172                 return;
173 
174             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
175             if (avatars->size() <= CAST_SIZE(num))
176                 return;
177 
178             const Avatar *const ava = avatars->at(num);
179             if (ava != nullptr)
180                 localPlayer->navigateTo(ava->getX(), ava->getY());
181         }
182 
updateNames()183         void updateNames()
184         {
185             if (socialWindow == nullptr)
186                 return;
187 
188             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
189 
190             const Map *const map = socialWindow->getMap();
191             if (map == nullptr)
192                 return;
193 
194             STD_VECTOR<Avatar*>::const_iterator i = avatars->begin();
195             const STD_VECTOR<Avatar*>::const_iterator i_end = avatars->end();
196             while (i != i_end)
197             {
198                 Avatar *const ava = *i;
199                 if (ava == nullptr)
200                     break;
201 
202                 const  MapItem *const item = map->findPortalXY(
203                     ava->getX(), ava->getY());
204                 if (item != nullptr)
205                 {
206                     const std::string name = strprintf("%s [%d %d]",
207                         item->getComment().c_str(),
208                         item->getX(), item->getY());
209                     ava->setName(name);
210                     ava->setOriginalName(name);
211                 }
212 
213                 ++i;
214             }
215         }
216 
getPortalIndex(const int x,const int y)217         int getPortalIndex(const int x, const int y)
218         {
219             if (socialWindow == nullptr)
220                 return -1;
221 
222             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
223             const Map *const map = socialWindow->getMap();
224             if (map == nullptr)
225                 return -1;
226 
227             STD_VECTOR<Avatar*>::const_iterator i = avatars->begin();
228             const STD_VECTOR<Avatar*>::const_iterator i_end = avatars->end();
229             unsigned num = 0;
230             while (i != i_end)
231             {
232                 const Avatar *const ava = *i;
233                 if (ava == nullptr)
234                     break;
235 
236                 if (ava->getX() == x && ava->getY() == y)
237                     return num;
238 
239                 ++i;
240                 num ++;
241             }
242             return -1;
243         }
244 
addPortal(const int x,const int y)245         void addPortal(const int x, const int y)
246         {
247             if ((socialWindow == nullptr) || (localPlayer == nullptr))
248                 return;
249 
250             const Map *const map = socialWindow->getMap();
251             if (map == nullptr)
252                 return;
253 
254             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
255             const MapItem *const portal = map->findPortalXY(x, y);
256             if (portal == nullptr)
257                 return;
258 
259             const std::string name = strprintf("%s [%d %d]",
260                 portal->getComment().c_str(), x, y);
261 
262             Avatar *const ava = new Avatar(name);
263             if (localPlayer != nullptr)
264                 ava->setOnline(localPlayer->isReachable(x, y, true));
265             else
266                 ava->setOnline(false);
267             ava->setLevel(-1);
268             ava->setType(portal->getType());
269             ava->setX(x);
270             ava->setY(y);
271             avatars->push_back(ava);
272         }
273 
removePortal(const int x,const int y)274         void removePortal(const int x, const int y)
275         {
276             if ((socialWindow == nullptr) || (localPlayer == nullptr))
277                 return;
278 
279             const Map *const map = socialWindow->getMap();
280             if (map == nullptr)
281                 return;
282 
283             STD_VECTOR<Avatar*> *const avatars = mBeings->getMembers();
284             STD_VECTOR<Avatar*>::iterator i = avatars->begin();
285             const STD_VECTOR<Avatar*>::iterator i_end = avatars->end();
286 
287             while (i != i_end)
288             {
289                 Avatar *ava = (*i);
290 
291                 if (ava == nullptr)
292                     break;
293 
294                 if (ava->getX() == x && ava->getY() == y)
295                 {
296                     delete ava;
297                     avatars->erase(i);
298                     return;
299                 }
300 
301                 ++ i;
302             }
303         }
304 
305     private:
306         BeingsListModel *mBeings;
307 };
308 
309 #endif  // GUI_WIDGETS_TABS_SOCIALNAVIGATIONTAB_H
310