OpenClonk
C4ObjectMenu.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 // Menus attached to objects; script created or internal
18 
19 #include "C4Include.h"
20 #include "object/C4ObjectMenu.h"
21 
22 #include "control/C4Control.h"
23 #include "game/C4Viewport.h"
25 #include "gui/C4MouseControl.h"
26 #include "object/C4Def.h"
27 #include "object/C4GameObjects.h"
28 #include "object/C4Object.h"
29 #include "object/C4ObjectCom.h"
30 #include "player/C4Player.h"
31 #include "player/C4PlayerList.h"
32 #include "script/C4AulExec.h"
33 
34 // -----------------------------------------------------------
35 // C4ObjectMenu
36 
38 {
39  Default();
40 }
41 
43 {
46  Object = ParentObject = RefillObject = nullptr;
48  UserMenu = false;
49  CloseQuerying = false;
50 }
51 
53 {
54  // abort if menu is permanented by script; stop endless recursive calls if user opens a new menu by CloseQuerying-flag
55  if (UserMenu && !CloseQuerying)
56  {
57  CloseQuerying = true;
58  bool fResult = false;
60  if (eCallbackType == CB_Object)
61  {
62  if (Object) fResult = !!Object->Call(PSF_MenuQueryCancel, &pars);
63  }
64  else if (eCallbackType == CB_Scenario)
65  fResult = !!::GameScript.Call(PSF_MenuQueryCancel, &pars);
66  CloseQuerying = false;
67  if (fResult) return true;
68  }
69  // close OK
70  return false;
71 }
72 
73 void C4ObjectMenu::LocalInit(C4Object *pObject, bool fUserMenu)
74 {
75  Object=pObject;
76  UserMenu=fUserMenu;
78  if (pObject) eCallbackType = CB_Object; else eCallbackType = CB_Scenario;
79 }
80 
81 bool C4ObjectMenu::Init(C4FacetSurface &fctSymbol, const char *szEmpty, C4Object *pObject, int32_t iExtra, int32_t iExtraData, int32_t iId, int32_t iStyle, bool fUserMenu)
82 {
83  if (!DoInit(fctSymbol, szEmpty, iExtra, iExtraData, iId, iStyle)) return false;
84  LocalInit(pObject, fUserMenu);
85  return true;
86 }
87 
88 bool C4ObjectMenu::InitRefSym(const C4TargetFacet &fctSymbol, const char *szEmpty, C4Object *pObject, int32_t iExtra, int32_t iExtraData, int32_t iId, int32_t iStyle, bool fUserMenu)
89 {
90  if (!DoInitRefSym(fctSymbol, szEmpty, iExtra, iExtraData, iId, iStyle)) return false;
91  LocalInit(pObject, fUserMenu);
92  return true;
93 }
94 
95 void C4ObjectMenu::OnSelectionChanged(int32_t iNewSelection)
96 {
97  // do selection callback
98  if (UserMenu)
99  {
100  C4AulParSet pars(iNewSelection, ParentObject);
101  if (eCallbackType == CB_Object && Object)
102  Object->Call(PSF_MenuSelection, &pars);
103  else if (eCallbackType == CB_Scenario)
105  }
106 }
107 
109 {
110  if (Object==pObj) { Object=nullptr; }
111  if (ParentObject==pObj) ParentObject=nullptr; // Reason for menu close anyway.
112  if (RefillObject==pObj) RefillObject=nullptr;
113  C4Menu::ClearPointers(pObj);
114 }
115 
117 {
118  for (C4Object *cObj : Objects)
119  if (cObj->Menu == this)
120  return cObj;
121  return nullptr;
122 }
123 
125 {
126  RefillObject=pObj;
127  NeedRefill=true;
128  Refill();
129 }
130 
131 bool C4ObjectMenu::DoRefillInternal(bool &rfRefilled)
132 {
133  // Variables
134  C4FacetSurface fctSymbol;
135  C4Object *pObj;
136  char szCaption[256+1],szCommand[256+1],szCommand2[256+1];
137  int32_t iCount;
138  C4Def *pDef;
139  C4IDList ListItems;
140  C4Object *pTarget;
141  C4Facet fctTarget;
142 
143  // Refill
144  switch (Identification)
145  {
146  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147  case C4MN_Activate:
148  // Clear items
149  ClearItems();
150  // Refill target
151  if (!(pTarget=RefillObject)) return false;
152  {
153  // Add target contents items
154  C4ObjectListIterator iter(pTarget->Contents);
155  while ((pObj = iter.GetNext(&iCount)))
156  {
157  pDef = pObj->Def;
158  if (pDef->NoGet) continue;
159  // Prefer fully constructed objects
160  if (~pObj->OCF & OCF_FullCon)
161  {
162  // easy way: only if first concat check matches
163  // this doesn't catch all possibilities, but that will rarely matter
164  C4Object *pObj2=pTarget->Contents.Find(pDef, ANY_OWNER, OCF_FullCon);
165  if (pObj2) if (pObj2->CanConcatPictureWith(pObj)) pObj = pObj2;
166  }
167  // Caption
168  sprintf(szCaption,LoadResStr("IDS_MENU_ACTIVATE"),(const char *) pObj->GetName());
169  // Picture
170  fctSymbol.Set(fctSymbol.Surface, 0,0,C4SymbolSize,C4SymbolSize);
171  pObj->Picture2Facet(fctSymbol);
172  // Commands
173  sprintf(szCommand,R"(SetCommand("Activate",Object(%d))&&ExecuteCommand())",pObj->Number);
174  sprintf(szCommand2,R"(SetCommand("Activate",nil,%d,0,Object(%d),%s)&&ExecuteCommand())",pTarget->Contents.ObjectCount(pDef->id),pTarget->Number,pDef->id.ToString());
175  // Add menu item
176  Add(szCaption,fctSymbol,szCommand,iCount,pObj,"",pDef->id,szCommand2,true,pObj->GetValue(pTarget, NO_OWNER));
177  // facet taken over (arrg!)
178  fctSymbol.Default();
179  }
180  }
181  break;
182  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183  case C4MN_Get:
184  case C4MN_Contents:
185  // Clear items
186  ClearItems();
187  // Refill target
188  if (!(pTarget = RefillObject)) return false;
189  {
190  // Add target contents items
191  C4ObjectListIterator iter(pTarget->Contents);
192  while ((pObj = iter.GetNext(&iCount)))
193  {
194  pDef = pObj->Def;
195  if (pDef->NoGet) continue;
196  // Prefer fully constructed objects
197  if (~pObj->OCF & OCF_FullCon)
198  {
199  // easy way: only if first concat check matches
200  // this doesn't catch all possibilities, but that will rarely matter
201  C4Object *pObj2 = pTarget->Contents.Find(pDef, ANY_OWNER, OCF_FullCon);
202  if (pObj2) if (pObj2->CanConcatPictureWith(pObj)) pObj = pObj2;
203  }
204  // Determine whether to get or activate
205  bool fGet = true;
206  if (!(pObj->OCF & OCF_Carryable)) fGet = false; // not a carryable item
208  {
209  if (Object && !!Object->Call(PSF_RejectCollection, &C4AulParSet(pObj->Def, pObj))) fGet = false; // collection rejected
210  }
211  if (!(pTarget->OCF & OCF_Entrance)) fGet = true; // target object has no entrance: cannot activate - force get
212  // Caption
213  sprintf(szCaption, LoadResStr(fGet ? "IDS_MENU_GET" : "IDS_MENU_ACTIVATE"), (const char *)pObj->GetName());
214  // Picture
215  fctSymbol.Set(fctSymbol.Surface, 0, 0, C4SymbolSize, C4SymbolSize);
216  pObj->Picture2Facet(fctSymbol);
217  // Primary command: get/activate single object
218  sprintf(szCommand, R"(SetCommand("%s", Object(%d)) && ExecuteCommand())", fGet ? "Get" : "Activate", pObj->Number);
219  // Secondary command: get/activate all objects of the chosen type
220  szCommand2[0] = 0; int32_t iAllCount;
221  if ((iAllCount = pTarget->Contents.ObjectCount(pDef->id)) > 1)
222  sprintf(szCommand2, R"(SetCommand("%s", nil, %d,0, Object(%d), %s) && ExecuteCommand())", fGet ? "Get" : "Activate", iAllCount, pTarget->Number, pDef->id.ToString());
223  // Add menu item (with object)
224  Add(szCaption, fctSymbol, szCommand, iCount, pObj, "", pDef->id, szCommand2);
225  fctSymbol.Default();
226  }
227  }
228  break;
229  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
230  default:
231  // Not an internal menu
232  return true;
233  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
234  }
235 
236  // Successfull internal refill
237  rfRefilled = true;
238  return true;
239 }
240 
242 {
243  if (!IsActive()) return;
244  // Immediate refill check by RefillObject contents count check
245  if (RefillObject)
248  // inherited
249  C4Menu::Execute();
250 }
251 
252 void C4ObjectMenu::OnUserSelectItem(int32_t Player, int32_t iIndex)
253 {
254  // queue.... 2do
256 }
257 
258 void C4ObjectMenu::OnUserEnter(int32_t Player, int32_t iIndex, bool fRight)
259 {
260  // object menu: Through queue 2do
262 }
263 
265 {
266  // Queue 2do
268 }
269 
271 {
272  // get viewport
273  C4Viewport *pVP = GetViewport();
274  if (!pVP) return false;
275  // is it an observer viewport?
276  if (pVP->fIsNoOwnerViewport)
277  // is this a synced menu?
279  // then don't control it!
280  return true;
281  // if the player is eliminated, do not control either!
282  if (!pVP->fIsNoOwnerViewport)
283  {
285  if (pPlr && pPlr->Eliminated) return true;
286  }
287  return false;
288 }
289 
291 {
292  // menu controlled by object controller
293  return Object ? Object->Controller : NO_OWNER;
294 }
295 
296 bool C4ObjectMenu::MenuCommand(const char *szCommand, bool fIsCloseCommand)
297 {
298  switch (eCallbackType)
299  {
300  case CB_Object:
301  // Object menu
302  if (Object) Object->MenuCommand(szCommand);
303  break;
304 
305  case CB_Scenario:
306  // Object menu with scenario script callback
307  ::AulExec.DirectExec(nullptr, szCommand, "MenuCommand");
308  break;
309 
310  case CB_None:
311  // TODO
312  break;
313  }
314 
315  return true;
316 }
C4AulExec AulExec
Definition: C4AulExec.cpp:29
const uint32_t OCF_Carryable
Definition: C4Constants.h:82
const int ANY_OWNER
Definition: C4Constants.h:138
const int C4SymbolSize
Definition: C4Constants.h:58
const uint32_t OCF_Entrance
Definition: C4Constants.h:90
const uint32_t OCF_FullCon
Definition: C4Constants.h:85
const int NO_OWNER
Definition: C4Constants.h:137
#define PSF_RejectCollection
Definition: C4GameScript.h:133
#define PSF_MenuSelection
Definition: C4GameScript.h:139
#define PSF_MenuQueryCancel
Definition: C4GameScript.h:83
C4Game Game
Definition: C4Globals.cpp:52
C4GameObjects Objects
Definition: C4Globals.cpp:48
C4MouseControl MouseControl
Definition: C4Globals.cpp:47
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
@ C4MN_AdjustPosition
Definition: C4Menu.h:62
@ C4MN_Activate
Definition: C4ObjectMenu.h:33
@ C4MN_Get
Definition: C4ObjectMenu.h:39
@ C4MN_Contents
Definition: C4ObjectMenu.h:44
@ CID_PlrControl
Definition: C4PacketBase.h:163
C4PlayerList Players
C4GameScriptHost GameScript
#define sprintf
Definition: Standard.h:162
C4Value DirectExec(C4PropList *p, const char *szScript, const char *szContext, bool fPassErrors=false, C4AulScriptContext *context=nullptr, bool parse_function=false)
Definition: C4AulExec.cpp:1012
void Add(C4PacketType eType, C4ControlPacket *pCtrl)
Definition: C4Control.h:82
Definition: C4Def.h:99
C4ID id
Definition: C4Def.h:101
int32_t NoGet
Definition: C4Def.h:144
C4Surface * Surface
Definition: C4Facet.h:117
void Set(const C4Facet &cpy)
Definition: C4FacetEx.h:46
void Default()
Definition: C4FacetEx.h:43
C4Control & Input
Definition: C4Game.h:82
C4PlayerControlDefs PlayerControlDefs
Definition: C4Game.h:92
C4Value Call(const char *szFunction, C4AulParSet *pPars=nullptr, bool fPassError=false)
const char * ToString() const
Definition: C4Id.h:56
Definition: C4Menu.h:123
virtual void Default()
Definition: C4Menu.cpp:246
bool Add(const char *szCaption, C4FacetSurface &fctSymbol, const char *szCommand, int32_t iCount=C4MN_Item_NoCount, C4Object *pObject=nullptr, const char *szInfoCaption=nullptr, C4ID idID=C4ID::None, const char *szCommand2=nullptr, bool fOwnValue=false, int32_t iValue=0, bool fIsSelectable=true)
Definition: C4Menu.cpp:350
void ClearPointers(C4Object *pObj)
Definition: C4Menu.cpp:1158
bool DoInit(C4FacetSurface &fctSymbol, const char *szEmpty, int32_t iExtra=C4MN_Extra_None, int32_t iExtraData=0, int32_t iId=0, int32_t iStyle=C4MN_Style_Normal)
Definition: C4Menu.cpp:300
bool Refill()
Definition: C4Menu.cpp:915
void ClearItems()
Definition: C4Menu.cpp:895
bool NeedRefill
Definition: C4Menu.h:135
C4Viewport * GetViewport() override
Definition: C4Menu.cpp:993
void Execute()
Definition: C4Menu.cpp:903
bool IsActive()
Definition: C4Menu.cpp:480
int32_t Identification
Definition: C4Menu.h:141
bool DoInitRefSym(const C4Facet &fctSymbol, const char *szEmpty, int32_t iExtra=C4MN_Extra_None, int32_t iExtraData=0, int32_t iId=0, int32_t iStyle=C4MN_Style_Normal)
Definition: C4Menu.cpp:307
int32_t Selection
Definition: C4Menu.h:137
int32_t GetPlayer()
int32_t GetValue(C4Object *pInBase, int32_t iForPlayer)
Definition: C4Object.cpp:791
void Picture2Facet(C4FacetSurface &cgo)
bool MenuCommand(const char *szCommand)
int32_t Controller
Definition: C4Object.h:109
uint32_t OCF
Definition: C4Object.h:132
C4NotifyingObjectList Contents
Definition: C4Object.h:151
bool CanConcatPictureWith(C4Object *pOtherObject) const
C4Def * Def
Definition: C4Object.h:141
C4Object * Find(C4Def *def, int owner=ANY_OWNER, DWORD dwOCF=OCF_All)
int ObjectCount(C4ID id=C4ID::None) const
C4Object * GetNext(int32_t *piCount)
void OnUserEnter(int32_t Player, int32_t iIndex, bool fRight) override
void OnUserSelectItem(int32_t Player, int32_t iIndex) override
C4Object * ParentObject
Definition: C4ObjectMenu.h:57
int32_t RefillObjectContentsCount
Definition: C4ObjectMenu.h:59
C4Object * GetParentObject() override
C4Object * Object
Definition: C4ObjectMenu.h:56
bool DoRefillInternal(bool &rfRefilled) override
bool IsCloseDenied() override
void Default() override
bool CloseQuerying
Definition: C4ObjectMenu.h:62
bool InitRefSym(const C4TargetFacet &fctSymbol, const char *szEmpty, C4Object *pObject, int32_t iExtra=C4MN_Extra_None, int32_t iExtraData=0, int32_t iId=0, int32_t iStyle=C4MN_Style_Normal, bool fUserMenu=false)
bool IsReadOnly() override
void SetRefillObject(C4Object *pObj)
void OnSelectionChanged(int32_t iNewSelection) override
void OnUserClose() override
bool MenuCommand(const char *szCommand, bool fIsCloseCommand) override
CallbackType eCallbackType
Definition: C4ObjectMenu.h:60
void LocalInit(C4Object *pObject, bool fUserMenu)
void ClearPointers(C4Object *pObj)
C4Object * RefillObject
Definition: C4ObjectMenu.h:58
bool Init(C4FacetSurface &fctSymbol, const char *szEmpty, C4Object *pObject, int32_t iExtra=C4MN_Extra_None, int32_t iExtraData=0, int32_t iId=0, int32_t iStyle=C4MN_Style_Normal, bool fUserMenu=false)
int32_t GetControllingPlayer() override
struct C4PlayerControlDefs::CInternalCons InternalCons
int32_t Eliminated
Definition: C4Player.h:83
C4Player * Get(int iPlayer) const
virtual const char * GetName() const
Definition: C4PropList.cpp:618
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:114
bool fIsNoOwnerViewport
Definition: C4Viewport.h:46