Added spawnCrystalItem
[ryzomcore.git] / ryzom / client / src / game_context_menu.cpp
blob363abdd807aaeebdad8a5b771ce2e9dd95907b0e
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2021 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
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 Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /////////////
25 // INCLUDE //
26 /////////////
27 #include "stdpch.h"
28 // Client.
29 #include "game_context_menu.h"
30 #include "interface_v3/interface_manager.h"
31 #include "nel/gui/ctrl_text_button.h"
32 #include "nel/gui/group_menu.h"
33 #include "entities.h"
34 #include "interface_v3/bot_chat_manager.h"
35 #include "interface_v3/guild_manager.h"
36 #include "interface_v3/people_interraction.h"
37 #include "continent_manager.h"
38 #include "main_loop.h"
39 #include "interface_v3/inventory_manager.h"
40 #include "motion/user_controls.h"
41 #include "sheet_manager.h"
42 #include "connection.h"
43 // GAME SHARE
44 #include "game_share/constants.h"
45 #include "game_share/properties.h"
46 #include "game_share/bot_chat_types.h"
47 #include "game_share/animal_type.h"
49 #include "r2/editor.h"
52 using namespace NLMISC;
53 using namespace std;
56 extern CContinentManager ContinentMngr;
58 // filter available programs depending on R2 mode
59 static uint32 filterAvailablePrograms(uint32 src)
61 return R2::getEditor().isDMing() ? 0 : src;
64 // ***************************************************************************
65 CGameContextMenu::CGameContextMenu()
67 _GroupMenu = NULL;
69 _MilkoAttackDisengage = NULL;
70 _ContextVal = NULL;
71 _AvailablePrograms = NULL;
72 _ServerTeamPresent = NULL;
73 for(uint i=0;i<NUM_MISSION_OPTIONS;i++)
74 _MissionOption[i]= NULL;
75 _ServerInDuel = NULL;
76 _ServerInPvpChallenge = NULL;
77 _WebPageTitle = NULL;
78 _OutpostSheet= NULL;
79 _OutpostRightToBannish= NULL;
80 for(uint i=0;i<BOTCHATTYPE::MaxR2MissionEntryDatabase;i++)
81 _MissionRing[i]= NULL;
85 // ***************************************************************************
86 void CGameContextMenu::init(const std::string &srcMenuId)
88 std::string menuId = srcMenuId.empty() ? std::string("game_context_menu") : srcMenuId;
89 CInterfaceManager *pIM= CInterfaceManager::getInstance();
91 _GroupMenu = dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getWindowFromId ("ui:interface:" + menuId + ""));
92 _ContextVal = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:TARGET:CONTEXT_VAL", false);
94 if(_GroupMenu == NULL)
96 nlwarning(("gamecontextmenu:init: 'ui:interface:" + menuId + "' window does not exist.").c_str());
97 return;
100 _GroupMilkoPad = "ui:interface:milko_pad";
101 if(_GroupMilkoPad != NULL)
103 _MilkoAttackDisengage = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:MK_ATTACK", false);
104 _MilkoAttDisBut1 = "ui:interface:milko_pad:content:mode1:mode1_content:milko_actions:action5";
105 _MilkoAttDisBut2 = "ui:interface:milko_pad:content:mode2:action5";
107 else
109 nlwarning("gamecontextmenu:init: 'ui:interface:milko_pad' window does not exist.");
112 if(_ContextVal == NULL)
114 nlwarning("gamecontextmenu:init: 'SERVER:TARGET:CONTEXT_VAL' node does not exist.");
115 return;
118 // Some DB links
119 _AvailablePrograms = NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:TARGET:CONTEXT_MENU:PROGRAMMES");
120 _ServerTeamPresent = NLGUI::CDBManager::getInstance()->getDbProp(TEAM_DB_PATH ":0:PRESENT", false);
121 _ServerInDuel = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:USER:IN_DUEL", false);
122 _ServerInPvpChallenge = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:USER:IN_PVP_CHALLENGE", false);
123 _WebPageTitle = NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:TARGET:CONTEXT_MENU:WEB_PAGE_TITLE", false);
124 _OutpostSheet = NLGUI::CDBManager::getInstance()->getDbProp("LOCAL:TARGET:CONTEXT_MENU:OUTPOST", false);
125 _OutpostRightToBannish = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:CHARACTER_INFO:PVP_OUTPOST:RIGHT_TO_BANISH", false);
128 // Some text Menu
129 _TextLootAction = "ui:interface:" + menuId + ":loot_action";
130 _TextQuartering = "ui:interface:" + menuId + ":quartering";
131 _TextAttack = "ui:interface:" + menuId + ":attack";
132 _TextDuel = "ui:interface:" + menuId + ":duel";
133 _TextUnDuel = "ui:interface:" + menuId + ":unduel";
134 _TextPvpChallenge = "ui:interface:" + menuId + ":pvp_challenge";
135 _TextUnPvpChallenge = "ui:interface:" + menuId + ":unpvp_challenge";
136 _TextExchange = "ui:interface:" + menuId + ":exchange";
137 _TextMount = "ui:interface:" + menuId + ":mount";
138 _TextFreeLook = "ui:interface:" + menuId + ":free_look";
139 _TextMove = "ui:interface:" + menuId + ":move";
140 _TextStop = "ui:interface:" + menuId + ":stop";
141 _TextDisengage = "ui:interface:" + menuId + ":disengage";
142 _TextUnseat = "ui:interface:" + menuId + ":unseat";
143 _TextInfo = "ui:interface:" + menuId + ":info";
144 _TextFollow = "ui:interface:" + menuId + ":follow";
145 _TextAssist = "ui:interface:" + menuId + ":assist";
146 _TextInvit = "ui:interface:" + menuId + ":invit";
147 _TextGuildInvit = "ui:interface:" + menuId + ":guild_invit";
148 _TextQuitTeam = "ui:interface:" + menuId + ":quit_team";
149 _TextAddToFriendList = "ui:interface:" + menuId + ":add_to_friend_list";
150 _TextTalk = "ui:interface:" + menuId + ":talk";
151 _TextInvisible = "ui:interface:" + menuId + ":invisible";
152 _TextInvulnerable = "ui:interface:" + menuId + ":invulnerable";
153 _TextGod = "ui:interface:" + menuId + ":god";
156 // Mission DB and Text link
157 for(uint k = 0; k < NUM_MISSION_OPTIONS; ++k)
159 _MissionOption[k] = NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:TARGET:CONTEXT_MENU:MISSIONS_OPTIONS:%d:TITLE", (int) k), false);
160 _TextMission[k] = toString(("ui:interface:" + menuId + ":mo%d").c_str(), (int) k);
163 // Mission Ring DB and Text link
164 for(uint k = 0; k < BOTCHATTYPE::MaxR2MissionEntryDatabase; ++k)
166 _MissionRing[k]= NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:TARGET:CONTEXT_MENU:MISSION_RING:%d:TITLE", k), false);
167 _TextMissionRing[k] = toString(("ui:interface:" + menuId + ":mr%d").c_str(), (int) k);
171 // BotChat menus
173 _TextNews = "ui:interface:" + menuId + ":news";
174 _TextNewsAgressive = "ui:interface:" + menuId + ":news_aggressive";
175 _TextTradeItem = "ui:interface:" + menuId + ":trade_item";
176 _TextTradeTeleport = "ui:interface:" + menuId + ":trade_teleport";
177 _TextTradeFaction = "ui:interface:" + menuId + ":trade_faction";
178 _TextTradeCosmetic = "ui:interface:" + menuId + ":trade_cosmetic";
179 _TextTradeGuildOptions = "ui:interface:" + menuId + ":trade_guild_options";
180 _TextTradeOutpostBuilding = "ui:interface:" + menuId + ":trade_outpost_building";
181 _TextTradeGuildRoleMaster = "ui:interface:" + menuId + ":trade_guild_role_master";
182 _TextTradePact = "ui:interface:" + menuId + ":trade_pact";
183 _TextTradePhrase = "ui:interface:" + menuId + ":trade_phrase";
184 _TextChooseMission = "ui:interface:" + menuId + ":choose_mission";
185 _TextCreateGuild = "ui:interface:" + menuId + ":create_guild";
186 _TextDynamicMission = "ui:interface:" + menuId + ":dynamic_mission";
187 _TextChooseZCCharge= "ui:interface:" + menuId + ":choose_zc_charge";
188 _TextChooseBuilding= "ui:interface:" + menuId + ":choose_building";
189 _TextBuyRM= "ui:interface:" + menuId + ":buy_rm";
190 _TextUpgradeRM= "ui:interface:" + menuId + ":upgrade_rm";
191 _TextCancelZCCharge= "ui:interface:" + menuId + ":cancel_zc_charge";
192 _TextDestroyBuilding= "ui:interface:" + menuId + ":destroy_building";
193 _TextOutpostState= "ui:interface:" + menuId + ":outpost_state";
194 _TextWebPage= "ui:interface:" + menuId + ":web_page";
195 _TextOutpostBanishPlayer= "ui:interface:" + menuId + ":outpost_bannish_player";
196 _TextOutpostBanishGuild= "ui:interface:" + menuId + ":outpost_bannish_guild";
199 // Pack Animals
200 _TextPAFollow= "ui:interface:" + menuId + ":pa_follow";
201 _TextPAStop= "ui:interface:" + menuId + ":pa_stop";
202 _TextPAFree= "ui:interface:" + menuId + ":pa_free";
203 _TextPAEnterStable= "ui:interface:" + menuId + ":pa_enter_stable";
204 _TextPAEnterBag= "ui:interface:" + menuId + ":pa_enter_bag";
206 // Forage source
207 _TextExtractRM= "ui:interface:" + menuId + ":extract_rm";
209 // Build Spire
210 _TextBuildTotem= "ui:interface:" + menuId + ":build_totem";
214 // ***************************************************************************
215 // tmp for debug
216 bool ForceTalkWithBot = false;
217 bool ForceTalkWithPlayer = false;
219 // ***************************************************************************
220 void CGameContextMenu::update()
222 H_AUTO (RZ_Interface_updateContextMenu )
224 if( !_ContextVal || !_GroupMenu )
225 return;
227 CProperties propValidation = CProperties(_ContextVal->getValue16());
229 // botChatPrograms
230 uint32 availablePrograms = filterAvailablePrograms((uint32) _AvailablePrograms->getValue32());
232 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
234 // Milko Pad
235 if ((_GroupMilkoPad != NULL) && (_GroupMilkoPad->getActive()))
237 if (canDisengage())
239 _MilkoAttackDisengage->setValue32(1);
240 if (_MilkoAttDisBut1)
241 _MilkoAttDisBut1->setHardText("uiMk_action5_1");
242 if (_MilkoAttDisBut2)
243 _MilkoAttDisBut2->setHardText("uiMk_action5_1");
245 else
247 _MilkoAttackDisengage->setValue32(0);
248 if (_MilkoAttDisBut1)
249 _MilkoAttDisBut1->setHardText("uiMk_action5_0");
250 if (_MilkoAttDisBut2)
251 _MilkoAttDisBut2->setHardText("uiMk_action5_0");
255 // Is the menu active
256 if(!_GroupMenu->getActive())
257 return;
259 updateContextMenuMissionsOptions( UserEntity->isRiding() );
261 updateContextMenuWebPage(availablePrograms);
263 updateContextMenuOutpostState(availablePrograms);
265 updateContextMenuOutpostBanish();
267 updateContextMenuMissionRing();
269 setupContextMenuCantTalk(); // can't talk by default
271 bool showGMOptions = (hasPrivilegeDEV() || hasPrivilegeSGM() || hasPrivilegeGM() || hasPrivilegeVG() || hasPrivilegeSG() || hasPrivilegeEM() || hasPrivilegeEG() || hasPrivilegeOBSERVER() || hasPrivilegeTESTER());
273 if (_TextInvisible)
274 _TextInvisible->setActive(showGMOptions);
276 if (_TextInvulnerable)
277 _TextInvulnerable->setActive(showGMOptions);
279 if (_TextGod)
280 _TextGod->setActive(showGMOptions);
283 // If mode Combat (no talk, no give, no mount, no extract_rm)
284 if(UserEntity->isFighting())
286 // Loot
287 if(_TextLootAction)
288 _TextLootAction->setActive(false);
289 // Quartering
290 if(_TextQuartering)
291 _TextQuartering->setActive(false);
292 // Disable talk, unless with a player
293 if (ForceTalkWithBot) // tmp
295 updateContextMenuTalkEntries(availablePrograms);
297 else if (ForceTalkWithPlayer)
299 setupContextMenuTalkWithPlayer();
301 else
302 if(selection && selection->Type == CEntityCL::Player)
304 setupContextMenuTalkWithPlayer();
307 // Exchange
308 if(_TextExchange)
309 _TextExchange->setActive(false);
310 // Disable mount
311 if(_TextMount)
312 _TextMount->setActive(false);
315 // Disable FreeLook.
316 if(_TextFreeLook)
317 _TextFreeLook->setActive(false);
318 // Disable unseat.
319 if(_TextUnseat)
320 _TextUnseat->setActive(false);
321 // Disable extraction
322 if(_TextExtractRM)
323 _TextExtractRM->setActive(false);
325 // Mount
326 else if(UserEntity->isRiding())
328 // Loot
329 if(_TextLootAction)
330 _TextLootAction->setActive(false);
331 // Quartering
332 if(_TextQuartering)
333 _TextQuartering->setActive(false);
334 // No talk when riding
335 // No exchange when riding
336 if(_TextExchange)
337 _TextExchange->setActive(false);
339 // Disable mount
340 if(_TextMount)
341 _TextMount->setActive(false);
344 // Disable Free Look
345 if(_TextFreeLook)
346 _TextFreeLook->setActive(false);
347 // Enable unseat
348 if(_TextUnseat)
349 _TextUnseat->setActive(true);
350 // Disable extraction
351 if(_TextExtractRM)
352 _TextExtractRM->setActive(false);
354 // Not in combat or riding mode.
355 else
357 // Loot
358 if(_TextLootAction)
360 _TextLootAction->setActive(false);
361 // Action possible only if the client is not already busy and the selection is able to do this with you..
362 if(selection && selection->isDead() && (selection->properties().lootable() || selection->properties().liftable())
363 && !R2::getEditor().isDMing()
365 _TextLootAction->setActive(true);
367 // Quartering
368 if(_TextQuartering)
370 _TextQuartering->setActive(false);
371 // Action possible only if the client is not already busy and the selection is able to do this with you..
372 if(selection && selection->isDead() && selection->properties().harvestable() && !R2::getEditor().isDMing())
373 _TextQuartering->setActive(true);
375 // talk ?
376 if (ForceTalkWithBot) // tmp
378 updateContextMenuTalkEntries(availablePrograms);
380 else if (ForceTalkWithPlayer)
382 setupContextMenuTalkWithPlayer();
384 else
385 if(UserEntity->selection() != UserEntity->slot()) // Talking again to yourself ?
387 if(selection)
389 if (selection->Type == CEntityCL::Player)
391 setupContextMenuTalkWithPlayer();
393 else
394 if(selection->properties().talkableTo())
396 if(!CBotChatManager::getInstance()->getCurrPage()) // Not talking
398 // Can talk with bot if not too far
399 CVectorD vect1 = selection->pos();
400 CVectorD vect2 = UserEntity->pos();
401 double distanceSquare = pow(vect1.x-vect2.x,2) + pow(vect1.y-vect2.y,2);
402 if (distanceSquare <= MaxTalkingDistSquare)
404 updateContextMenuTalkEntries(availablePrograms);
406 // Special case for buildings
407 if (distanceSquare <= MaxTalkingOutpostBuildingDistSquare)
408 _OkTextTradeOutpostBuilding = ((availablePrograms & (1 << BOTCHATTYPE::TradeOutpostBuilding)) != 0);
413 // Exchange
414 if(_TextExchange)
416 // Action possible only if the client is not already busy and the selection is able to do this with you..
417 if(selection && selection->isPlayer() && selection->properties().canExchangeItem())
418 _TextExchange->setActive(!UserEntity->isBusy());
419 else
420 _TextExchange->setActive(false);
422 // Enable Free Look
423 if(_TextFreeLook)
424 _TextFreeLook->setActive(true);
425 // Disable unseat
426 if(_TextUnseat)
427 _TextUnseat->setActive(false);
428 // Enable extraction for a forage source
429 if(_TextExtractRM)
431 _TextExtractRM->setActive(false);
432 if ( selection && selection->isForageSource() )
433 _TextExtractRM->setActive(true);
437 // Enable attack mode
438 if (_TextAttack)
439 _TextAttack->setActive(canAttack());
442 // get current continent to check fame
443 string continent = ContinentMngr.cur()->SheetName;
444 sint8 fameValue = 0;
445 uint fameIndex;
446 if (continent == "lesfalaises.continent")
447 fameIndex = CStaticFames::getInstance().getFactionIndex("matis");
448 else if (continent == "fyros.continent")
449 fameIndex = CStaticFames::getInstance().getFactionIndex("fyros");
450 else if (continent == "tryker.continent")
451 fameIndex = CStaticFames::getInstance().getFactionIndex("tryker");
452 else if (continent == "lepaysmalade.continent")
453 fameIndex = CStaticFames::getInstance().getFactionIndex("zorai");
456 if (fameIndex != CStaticFames::INVALID_FACTION_INDEX)
458 CCDBNodeLeaf *pLeafFame = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:FAME:PLAYER%d:VALUE", fameIndex), false);
459 if (pLeafFame != NULL)
460 fameValue = pLeafFame->getValue8();
464 bool enable_rumors = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENABLE_RUMORS")->getValueBool();
466 if (_TextNews)
467 _TextNews->setActive(enable_rumors && !UserEntity->isFighting() && !UserEntity->isRiding() && selection && !canAttack() && selection->isNPC() && fameValue >= -30);
469 if (_TextNewsAgressive)
470 _TextNewsAgressive->setActive(enable_rumors && !UserEntity->isFighting() && !UserEntity->isRiding() && selection && !canAttack() && selection->isNPC() && fameValue < -30);
473 if (_TextDuel && _TextUnDuel)
475 if ((!UserEntity->isRiding()) && (_ServerInDuel->getValue8() != 0))
477 _TextDuel->setActive(false);
478 _TextUnDuel->setActive(true);
480 else if (canDuel())
482 _TextDuel->setActive(true);
483 _TextUnDuel->setActive(false);
485 else
487 _TextDuel->setActive(false);
488 _TextUnDuel->setActive(false);
492 if (_TextPvpChallenge && _TextUnPvpChallenge)
494 if ((!UserEntity->isRiding()) && (_ServerInPvpChallenge->getValue8() != 0))
496 _TextPvpChallenge->setActive(false);
497 _TextUnPvpChallenge->setActive(true);
499 else if (canPvpChallenge())
501 _TextPvpChallenge->setActive(true);
502 _TextUnPvpChallenge->setActive(false);
504 else
506 _TextPvpChallenge->setActive(false);
507 _TextUnPvpChallenge->setActive(false);
511 // Enable disengage mode
512 if (_TextDisengage)
513 _TextDisengage->setActive(canDisengage());
515 // Enable Autowalk
516 if(_TextMove)
517 _TextMove->setActive(!UserControls.autowalkState());
518 // Enable Stop Autowalk
519 if(_TextStop)
520 _TextStop->setActive(UserControls.autowalkState());
522 // Disable player properties
523 if(_TextInfo)
524 _TextInfo->setActive(selection && (!selection->isForageSource()));
526 // Follow
527 if(_TextFollow)
529 // Action possible only if the client is not already busy and the selection is able to do this with you..
530 _TextFollow->setActive(
531 selection &&
532 (selection->slot() != UserEntity->slot()) &&
533 (!selection->isForageSource()) &&
534 (selection->isDead()==false) &&
535 (((availablePrograms & (1 << BOTCHATTYPE::DontFollow)) == 0)));
536 // See also below for mount/packer
539 // Assist
540 if(_TextAssist)
542 // Action possible only if the client is not already busy and the selection is able to do this with you..
543 _TextAssist->setActive(!R2::getEditor().isDMing() && selection && (selection->slot() != UserEntity->slot()) && (!selection->isForageSource()) && (selection->isDead()==false));
544 // See also below for mount/packer
547 // Invite
548 if(_TextInvit)
550 bool invitable = false;
551 // User should not be flagged as invitable by himself, so no need to check that selection is not the user
552 if(selection && selection->isPlayer() && selection->properties().invitable() && propValidation.invitable() )
554 invitable = true;
556 // Grey/Ungrey the entry.
557 _TextInvit->setActive(invitable);
560 // Guild Invit
561 if(_TextGuildInvit)
563 // if server OK.
564 if(filterAvailablePrograms(_AvailablePrograms->getValue32())&(1 << BOTCHATTYPE::GuildInviteFlag))
565 _TextGuildInvit->setActive (true);
566 else
567 _TextGuildInvit->setActive (false);
570 // Active "Quit Team" if you are a member of one.
571 if(_TextQuitTeam)
573 if (_ServerTeamPresent)
575 _TextQuitTeam->setActive( _ServerTeamPresent->getValueBool() );
579 // Invite to friend list (only if target is a player, and not a friend already)
580 if(_TextAddToFriendList)
582 _TextAddToFriendList->setActive(false);
583 if (selection && selection->Type == CEntityCL::Player)
585 if (!selection->getEntityName().empty())
587 sint peopleIndex = PeopleInterraction.FriendList.getIndexFromName(selection->getEntityName());
588 if (peopleIndex == -1) // not already in friend list
590 _TextAddToFriendList->setActive(true);
596 // Pack/Mount Animal
597 if ( _TextMount )
598 _TextMount->setActive(false);
599 if(selection && (selection->isUserPackAnimal() || (selection->isUserMount())))
601 // Get the index of the selected animal, if owned by the player
602 sint animalIndex;
603 if ( ! selection->getPackAnimalIndexInDB( animalIndex ) )
604 animalIndex = -1;
606 // Disable 'Mount' if server says so
607 CViewTextMenu *pTextMount = NULL;
608 if ( propValidation.mountable() )
609 pTextMount = _TextMount;
610 else if (_TextMount)
611 _TextMount->setActive( false ); // pTextMount remains NULL
613 // Enable/disable various menu items
614 bool ok = testMenuOptionForPackAnimal( selection, animalIndex, true, _TextPAFollow, _TextPAStop, _TextPAFree,
615 _TextPAEnterStable, NULL /*no 'leave stable' in context menu*/, pTextMount,
616 NULL /*unmount always active in context menu when the character is riding*/, _TextPAEnterBag, NULL);
618 // Follow & assist special case
619 if ( _TextFollow )
620 _TextFollow->setActive( false ); // can't follow own pet
621 if ( _TextAssist )
622 _TextAssist->setActive( false ); // can't assist a pet
624 // Write the selected pack animal, for future "beast_order" action handler
625 if(ok)
627 CInterfaceManager *pIM= CInterfaceManager::getInstance();
628 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp("UI:GCM_BEAST_SELECTED", false);
629 // beast_order AH start with 1 (0 for ALL beasts)
630 if(node)
631 node->setValue32(animalIndex+1);
634 else
636 if (_TextPAFollow)
637 _TextPAFollow->setActive(false);
638 if (_TextPAStop)
639 _TextPAStop->setActive(false);
640 if (_TextPAEnterStable)
641 _TextPAEnterStable->setActive(false);
642 if (_TextPAEnterBag)
643 _TextPAEnterBag->setActive(false);
646 // Remove Free option to prevent miss click
647 if (_TextPAFree)
648 _TextPAFree->setActive(false);
651 // build spire
652 if(_TextBuildTotem)
654 _TextBuildTotem->setActive(false);
655 if( availablePrograms & ( 1 << BOTCHATTYPE::Totem ) )
657 _TextBuildTotem->setActive(true);
661 // Apply real activation of Talk Texts.
662 applyTextTalk();
666 // ***************************************************************************
667 bool CGameContextMenu::canAttack()
669 if (R2::getEditor().isDMing()) return false;
670 bool ret = false;
671 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
673 if (UserEntity->isFighting() || UserEntity->isRiding())
674 return ret;
676 // To enter in combat, the user should not be talking.
677 if(!CBotChatManager::getInstance()->getCurrPage()) // Not talking
679 // If there is a selection.
680 if (selection && selection->isDead() == false)
682 uint32 availablePrograms = (uint32) filterAvailablePrograms(_AvailablePrograms->getValue32());
684 if(selection->properties().attackable() || (availablePrograms & (1<<BOTCHATTYPE::Attackable)))
685 ret = true;
688 return ret;
691 // ***************************************************************************
692 bool CGameContextMenu::canDuel()
694 if (UserEntity->isFighting() || UserEntity->isRiding())
695 return false;
697 // To enter in combat, the user should not be talking.
698 if(CBotChatManager::getInstance()->getCurrPage()) // Talking ?
699 return false;
701 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
702 if (selection == NULL)
703 return false;
705 if (selection->isPlayer())
706 if (selection->isDead() == false)
707 return true;
709 return false;
712 // ***************************************************************************
713 bool CGameContextMenu::canPvpChallenge()
715 if (UserEntity->isFighting() || UserEntity->isRiding())
716 return false;
718 // To enter in combat, the user should not be talking.
719 if(CBotChatManager::getInstance()->getCurrPage()) // Talking ?
720 return false;
722 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
723 if (selection == NULL)
724 return false;
726 if (selection->isPlayer())
727 if (selection->isDead() == false)
728 return true;
730 return false;
733 // ***************************************************************************
734 bool CGameContextMenu::canDisengage()
736 if (UserEntity->isFighting())
737 return true;
738 else
739 return false;
742 // ***************************************************************************
743 bool CGameContextMenu::canTeamKick()
745 CEntityCL *selection = EntitiesMngr.entity(UserEntity->selection());
746 if (selection != NULL)
748 sint n = PeopleInterraction.TeamList.getIndexFromName(selection->getEntityName());
749 if (n >= 0)
750 return true;
752 return false;
755 // ***************************************************************************
756 void CGameContextMenu::updateContextMenuMissionsOptions( bool forceHide )
758 for(uint k = 0; k < NUM_MISSION_OPTIONS; ++k)
760 CViewTextMenu *pVTM = _TextMission[k];
761 if (pVTM)
763 if ( _MissionOption[k] && (!forceHide) )
765 uint32 textID = (uint32) _MissionOption[k]->getValue32();
766 if (textID)
768 string result;
769 bool res = STRING_MANAGER::CStringManagerClient::instance()->getDynString(textID, result);
770 if (!res)
772 result = NLMISC::CI18N::get("uiMissionOptionNotReceived");
774 if (result == string("Qui etes-vous ?")
775 || result == string("Wer bist Du?")
776 || result == string("Who are you?")
777 || result == string("Quién eres tú?")
778 || result == string("Кто ты?"))
780 pVTM->setActive(false);
782 else
784 pVTM->setText(result);
785 pVTM->setActive(true);
788 else
790 pVTM->setText("");
791 pVTM->setActive(false);
794 else
796 pVTM->setText("");
797 pVTM->setActive(false);
803 // ***************************************************************************
804 void CGameContextMenu::updateContextMenuWebPage(uint options)
806 // Show the web page (title must be present)
807 _OkTextWebPage= ((options & (1 << BOTCHATTYPE::WebPageFlag)) != 0);
808 if(_OkTextWebPage)
809 _OkTextWebPage= _WebPageTitle && _WebPageTitle->getValue32()!=0;
811 // Change the WebPage text, when available
812 CViewTextMenu *pVTM = _TextWebPage;
813 if (pVTM)
815 if ( _WebPageTitle )
817 uint32 textID = (uint32) _WebPageTitle->getValue32();
818 if (textID)
820 string result;
821 bool res = STRING_MANAGER::CStringManagerClient::instance()->getDynString(textID, result);
822 if (!res)
824 result = NLMISC::CI18N::get("uiWebPageNameNotReceived");
826 pVTM->setText(result);
828 else
830 pVTM->setText("");
833 else
835 pVTM->setText("");
839 // apply the active
840 if (_TextWebPage) _TextWebPage->setActive(_OkTextWebPage);
843 // ***************************************************************************
844 void CGameContextMenu::updateContextMenuOutpostState(uint options)
846 CSheetId outpostSheet;
848 // Outpost ok?
849 _OkTextOutpostState= false;
850 if ( (options & (1 << BOTCHATTYPE::OutpostFlag)) != 0 && _OutpostSheet)
852 // check that the outpost sheet is correct
853 outpostSheet= _OutpostSheet->getValue32();
854 CEntitySheet *s= SheetMngr.get(outpostSheet);
855 if(s && s->Type == CEntitySheet::OUTPOST)
856 _OkTextOutpostState= true;
859 // Fill the text
860 if(_OkTextOutpostState)
862 CViewTextMenu *pVTM = _TextOutpostState;
863 if (pVTM)
864 pVTM->setText(STRING_MANAGER::CStringManagerClient::getOutpostLocalizedName(outpostSheet));
867 // apply the active
868 if (_TextOutpostState) _TextOutpostState->setActive(_OkTextOutpostState);
871 // ***************************************************************************
872 void CGameContextMenu::updateContextMenuOutpostBanish()
874 bool okForBanPlayer= false;
875 bool okForBanGuild= false;
877 // Test if the player can ban the targeted player / player's guild
878 extern void outpostTestUserCanBan(CCDBNodeLeaf *dbBanRight, bool &, bool &);
879 outpostTestUserCanBan(_OutpostRightToBannish, okForBanPlayer, okForBanGuild);
881 // validate text
882 if(_TextOutpostBanishPlayer) _TextOutpostBanishPlayer->setActive(okForBanPlayer);
883 if(_TextOutpostBanishGuild) _TextOutpostBanishGuild->setActive(okForBanGuild);
886 // ***************************************************************************
887 void CGameContextMenu::updateContextMenuMissionRing()
889 for(uint k = 0; k < BOTCHATTYPE::MaxR2MissionEntryDatabase; ++k)
891 CViewTextMenu *pVTM = _TextMissionRing[k];
892 if (pVTM)
894 uint32 textId= 0;
895 if ( _MissionRing[k] )
896 textId= _MissionRing[k]->getValue32();
897 // if the textId is ok and Flag is set.
898 if ( textId )
900 string result;
901 bool res = STRING_MANAGER::CStringManagerClient::instance()->getDynString(textId, result);
902 if (!res)
904 result = NLMISC::CI18N::get("uiMissionRingNameNotReceived");
906 pVTM->setText(result);
907 pVTM->setActive(true);
909 else
911 pVTM->setText("");
912 pVTM->setActive(false);
918 // ***************************************************************************
919 void CGameContextMenu::updateContextMenuTalkEntries(uint options)
921 if (ClientCfg.Local)
923 options = std::numeric_limits<uint>::max(); // in local mode, force all options to be shown (for debug)
925 // news
926 _OkTextNews= true; //((options & (1 << BOTCHATTYPE::NewsFlag)));
927 // trade
928 _OkTextTradeItem= ((options & (1 << BOTCHATTYPE::TradeItemFlag)) != 0);
929 _OkTextTradeTeleport= ((options & (1 << BOTCHATTYPE::TradeTeleportFlag)) != 0);
930 _OkTextTradeFaction= ((options & (1 << BOTCHATTYPE::TradeFactionFlag)) != 0);
931 _OkTextTradeCosmetic= ((options & (1 << BOTCHATTYPE::TradeCosmeticFlag)) != 0);
932 _OkTextTradeGuildOptions = ((options & (1 << BOTCHATTYPE::TradeBuildingOptions)) != 0);
933 _OkTextTradeOutpostBuilding = ((options & (1 << BOTCHATTYPE::TradeOutpostBuilding)) != 0);
934 _OkTextTradeGuildRoleMaster = ((options & (1 << BOTCHATTYPE::GuildRoleMaster)) != 0);
935 _OkTextTradePact= ((options & (1 << BOTCHATTYPE::TradePactFlag)) != 0);
936 _OkTextTradePhrase= ((options & (1 << BOTCHATTYPE::TradePhraseFlag)) != 0);
937 // choose mission
938 _OkTextChooseMission= ((options & (1 << BOTCHATTYPE::ChooseMissionFlag)) != 0);
939 // create guild
940 _OkTextCreateGuild= ((options & (1 << BOTCHATTYPE::CreateGuildFlag)) != 0);
941 // New Yoyo BotChat
942 _OkTextChooseZCCharge= ((options & (1 << BOTCHATTYPE::AskGuildDutyFlag)) != 0);
943 _OkTextCancelZCCharge= ((options & (1 << BOTCHATTYPE::CancelGuildDutyFlag)) != 0);
945 /*_OkTextBuyRM= ((options & (1 << BOTCHATTYPE::)) != 0);
946 _OkTextUpgradeRM= ((options & (1 << BOTCHATTYPE::)) != 0);
947 _OkTextDestroyBuilding= ((options & (1 << BOTCHATTYPE::)) != 0);*/
948 // TODO BOTCHAT: RM Buy/Upgrade.
949 // TODO BOTCHAT: Declare war no more through "Mission Option"
950 // TODO BOTCHAT: Destroy Building only if already created
951 // TODO BOTCHAT: ZCBuilder is deprecated, as is _OkTextChooseBuilding
952 // TODO BOTCHAT: _OkTextDynamicMission is deprecated
953 _OkTextDynamicMission= false;
954 _OkTextBuyRM= false;
955 _OkTextUpgradeRM= false;
956 _OkTextChooseBuilding= false;
957 _OkTextDestroyBuilding= _OkTextChooseBuilding;
961 // ***************************************************************************
962 void CGameContextMenu::setupContextMenuCantTalk()
964 updateContextMenuTalkEntries(0);
965 _OkTextTalk= false;
968 // ***************************************************************************
969 void CGameContextMenu::setupContextMenuTalkWithPlayer()
971 _OkTextTalk= true;
974 // ***************************************************************************
975 void CGameContextMenu::applyTextTalk()
977 if (_TextTradeItem) _TextTradeItem->setActive(_OkTextTradeItem);
978 if (_TextTradeTeleport) _TextTradeTeleport->setActive(_OkTextTradeTeleport);
979 if (_TextTradeFaction) _TextTradeFaction->setActive(_OkTextTradeFaction);
980 if (_TextTradeCosmetic) _TextTradeCosmetic->setActive(_OkTextTradeCosmetic);
981 if (_TextTradeGuildOptions) _TextTradeGuildOptions->setActive(_OkTextTradeGuildOptions);
982 if (_TextTradeOutpostBuilding) _TextTradeOutpostBuilding->setActive(_OkTextTradeOutpostBuilding);
983 if (_TextTradeGuildRoleMaster) _TextTradeGuildRoleMaster->setActive(_OkTextTradeGuildRoleMaster);
984 if (_TextTradePact) _TextTradePact->setActive(_OkTextTradePact);
985 if (_TextTradePhrase) _TextTradePhrase->setActive(_OkTextTradePhrase);
986 if (_TextChooseMission) _TextChooseMission->setActive(_OkTextChooseMission);
987 if (_TextCreateGuild)
989 _TextCreateGuild->setActive(_OkTextCreateGuild);
990 // If the player is already in a guild set the text grayed
991 _TextCreateGuild->setGrayed(CGuildManager::getInstance()->isInGuild());
994 if (_TextDynamicMission) _TextDynamicMission->setActive(_OkTextDynamicMission);
995 if (_TextTalk) _TextTalk->setActive(_OkTextTalk);
996 if (_TextChooseZCCharge) _TextChooseZCCharge->setActive(_OkTextChooseZCCharge);
997 if (_TextChooseBuilding) _TextChooseBuilding->setActive(_OkTextChooseBuilding);
998 if (_TextBuyRM) _TextBuyRM->setActive(_OkTextBuyRM);
999 if (_TextUpgradeRM) _TextUpgradeRM->setActive(_OkTextUpgradeRM);
1000 if (_TextCancelZCCharge) _TextCancelZCCharge->setActive(_OkTextCancelZCCharge);
1001 if (_TextDestroyBuilding) _TextDestroyBuilding->setActive(_OkTextDestroyBuilding);
1004 // ***************************************************************************
1007 * Enable/disable various menu items for animals.
1008 * selectedAnimalInVision can be NULL (out of vision)
1009 * index can be -1 (no owned animal)
1010 * Any CViewTextMenu* can be NULL
1012 bool testMenuOptionForPackAnimal( CEntityCL* selectedAnimalInVision, uint index, bool clearAll,
1013 CViewTextMenu *pFollow, CViewTextMenu *pStop, CViewTextMenu *pFree,
1014 CViewTextMenu *pEnterStable, CViewTextMenu *pLeaveStable,
1015 CViewTextMenu *pMount, CViewTextMenu *pUnmount,
1016 CViewTextMenu *pEnterBag, CViewTextMenu *pLeaveBag)
1018 if ( clearAll )
1020 // Disable and gray all by default
1021 if(pFollow) { pFollow->setActive(false); pFollow->setGrayed(true); }
1022 if(pStop) { pStop->setActive(false); pStop->setGrayed(true); }
1023 if(pFree) { pFree->setActive(false); pFree->setGrayed(true); }
1024 if(pEnterStable) { pEnterStable->setActive(false); pEnterStable->setGrayed(true); }
1025 if(pLeaveStable) { pLeaveStable->setActive(false); pLeaveStable->setGrayed(true); }
1026 if(pEnterBag) { pEnterBag->setActive(false); pEnterBag->setGrayed(true); }
1027 if(pLeaveBag) { pLeaveBag->setActive(false); pLeaveBag->setGrayed(false); }
1028 if(pMount) { pMount->setActive(false); pMount->setGrayed(true); }
1029 if(pUnmount) { pUnmount->setActive(false); pUnmount->setGrayed(true); }
1032 // Don't enable anything if index not found (e.g. the character is not the owner of the animal)
1033 if ( (index == (uint)-1) || (!UserEntity) )
1034 return false;
1036 // Get animal status and type
1037 CInterfaceManager *pIM= CInterfaceManager::getInstance();
1038 CCDBNodeLeaf *node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", index), false);
1039 if(!node) return false;
1040 ANIMAL_STATUS::EAnimalStatus status= (ANIMAL_STATUS::EAnimalStatus)node->getValue32();
1041 node= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:TYPE", index), false);
1042 if(!node) return false;
1043 ANIMAL_TYPE::EAnimalType anitype= (ANIMAL_TYPE::EAnimalType)node->getValue32();
1045 if (anitype != ANIMAL_TYPE::Pet)
1047 if (pEnterBag)
1048 pEnterBag->setActive(false);
1049 if (pLeaveBag)
1050 pLeaveBag->setActive(false);
1053 // COMMON PART FOR ALL TYPES OF ANIMAL
1055 // Is the character mounted on the animal?
1056 bool userIsMountedOnIt = false;
1057 if ( selectedAnimalInVision && (anitype == ANIMAL_TYPE::Mount) && UserEntity->isRiding() )
1059 uint8 mountSlot = (uint8)IngameDbMngr.getProp( "Entities:E" + toString(UserEntity->slot()) + ":P" + toString(CLFECOMMON::PROPERTY_ENTITY_MOUNTED_ID));
1060 userIsMountedOnIt = (mountSlot == selectedAnimalInVision->slot());
1063 bool onLandscape = ANIMAL_STATUS::isInLandscape(status);
1064 double distanceSquare = 0;
1065 if ( selectedAnimalInVision )
1067 CVectorD vect1 = selectedAnimalInVision->pos();
1068 CVectorD vect2 = UserEntity->pos();
1069 distanceSquare = pow(vect1.x-vect2.x,2) + pow(vect1.y-vect2.y,2);
1072 bool onBag = ANIMAL_STATUS::isInBag(status);
1074 // Enable option only if pack animal present
1075 if(ANIMAL_STATUS::isSpawned(status))
1077 bool canEnterLeaveStable= ANIMAL_STATUS::canEnterLeaveStable(status);
1079 if (!userIsMountedOnIt)
1081 if(pFollow && onLandscape) pFollow->setActive(true);
1082 if(pStop && onLandscape) pStop->setActive(true);
1084 // Enter/leave stable are only displayed when near a stable ('canEnterLeaveStable')
1085 if(pEnterStable && onLandscape && canEnterLeaveStable) pEnterStable->setActive(true);
1086 if(pLeaveStable && ANIMAL_STATUS::isInStable(status) && canEnterLeaveStable) pLeaveStable->setActive(true);
1088 // Can always free, dead/alive, in or out stable animals
1089 if(pFree)
1091 pFree->setActive(true);
1092 pFree->setGrayed(false);
1096 // If alive (and close to the character), ungray all
1097 if(ANIMAL_STATUS::isAlive(status))
1099 if (onLandscape && selectedAnimalInVision && (distanceSquare <= MaxAnimalCommandDistSquare))
1101 if(pFollow) pFollow->setGrayed(false);
1102 if(pStop) pStop->setGrayed(false);
1103 if(pEnterStable) pEnterStable->setGrayed(false);
1104 if (pEnterBag && !onBag)
1105 pEnterBag->setGrayed(false);
1107 if (pLeaveBag && onBag)
1108 pLeaveBag->setActive(true);
1110 if (pEnterBag && !onBag && anitype == ANIMAL_TYPE::Pet)
1111 pEnterBag->setActive(true);
1113 if(pLeaveStable) pLeaveStable->setGrayed(false);
1117 // Specific part for mountable animal
1118 if ((anitype == ANIMAL_TYPE::Mount) &&
1119 (ANIMAL_STATUS::isSpawned(status)) && onLandscape)
1121 if ( userIsMountedOnIt )
1123 // Always allow to unmount the mounted mount
1124 if(pUnmount) pUnmount->setActive(true);
1125 if(pUnmount) pUnmount->setGrayed(false);
1127 else
1129 if(pMount &&
1130 ((!selectedAnimalInVision) || selectedAnimalInVision->properties().mountable()))
1132 // Display 'Mount' if the entity is of mountable type
1133 pMount->setActive(true);
1135 // Enable 'Mount' if the character is not busy and the entity is alive and close enough
1136 if(ANIMAL_STATUS::isAlive(status) && (!UserEntity->isRiding()) &&
1137 (!UserEntity->isFighting()) && (!UserEntity->isBusy()))
1139 if(selectedAnimalInVision && (distanceSquare <= MaxAnimalCommandDistSquare))
1141 pMount->setGrayed(false);
1148 return true;