Advanced Strategic Command
eventeditor.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Advanced Strategic Command; http://www.asc-hq.de
3  Copyright (C) 1994-2010 Martin Bickel and Marc Schellenberger
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; see the file COPYING. If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  Boston, MA 02111-1307 USA
19 */
20 
21 
22 #include <sstream>
23 #include <pgimage.h>
24 
25 #include <pgpropertyeditor.h>
26 #include <pgpropertyfield_integer.h>
27 
28 #include "eventeditor.h"
29 #include "../paradialog.h"
30 #include "../gamemap.h"
31 #include "../spfst.h"
32 #include "../gameeventsystem.h"
33 #include "../gameevents.h"
34 
35 #include "../widgets/dropdownselector.h"
36 #include "../widgets/multilistbox.h"
37 
38 class EventEditor : public ASC_PG_Dialog {
39  private:
40  vector<ASCString> triggerNames;
41  vector<ASCString> actionNames;
42 
43  DropDownSelector* eventType;
44  DropDownSelector* triggerConnection;
45  PG_LineEdit* description;
46  Event* event;
47  bool result;
48  PG_ListBox* playerlistbox;
49  PG_PropertyEditor* properties;
50 
51  GameMap* gamemap;
52 
53  bool setupEvent()
54  {
55  if ( event->action )
56  event->action->setup();
57  return true;
58  }
59 
60  void actionSelected( int i )
61  {
62  if ( i < 0 )
63  return;
64 
65  EventActionID eai = eventActionFactory::Instance().getID( actionNames.at(i) );
66 
67  if ( !event->action )
68  event->spawnAction( eai );
69  else
70  if ( event->action->getActionID() != eai ) {
71  delete event->action;
72  event->action = NULL;
73  event->spawnAction( eai );
74  }
75 
76  event->action->setup();
77  }
78 
79  bool setupTrigger( PG_Widget* w, int num )
80  {
81  if ( event->trigger.size() > num )
82  if ( event->trigger[num] )
83  event->trigger[num]->setup();
84 
85  return true;
86  }
87 
88  void triggerSelected( int type, int num )
89  {
90  if ( type>= 0 ) {
91  EventTriggerID triggerID = eventTriggerFactory::Instance().getID( triggerNames.at(type) );
92 
93  if ( event->trigger.size() <= num ) {
94  int oldSize = event->trigger.size();
95  event->trigger.resize(num+1);
96  for ( int i = oldSize; i < event->trigger.size(); ++i )
97  if ( i != num )
98  event->trigger[i] = event->spawnTrigger( Trigger_NothingFalse );
99 
100  event->trigger[num] = event->spawnTrigger( triggerID );
101  event->trigger[num]->setup();
102  } else {
103  if ( event->trigger[num]->getTriggerID() == triggerID )
104  event->trigger[num]->setup();
105  else {
106  delete event->trigger[num];
107  event->trigger[num] = event->spawnTrigger( triggerID );
108  event->trigger[num]->setup();
109  }
110  }
111  }
112  }
113 
114  bool invertTrigger( bool invert, int e )
115  {
116  if ( event->trigger.size() > e ) {
117  event->trigger[e]->invert = invert;
118  return true;
119  } else
120  return false;
121  }
122 
123 
124  bool ok()
125  {
126  if ( !properties->Apply() )
127  return false;
128 
129  if ( event->trigger.size() < 1 ) {
130  warningMessage( "no trigger defined !" );
131  return false;
132  }
133 
134  if ( !event->action ) {
135  warningMessage ( "no action defined !" );
136  return false;
137  }
138  if ( event->reArmNum && event->delayedexecution.turn < 1 ) {
139  warningMessage ( "without delayed execution, reArming the event makes no sense !" );
140  return false;
141  }
142 
143  event->description = description->GetText();
144 
145  if ( triggerConnection->GetSelectedItemIndex() == 0 )
146  event->triggerConnection = Event::AND;
147  else
148  event->triggerConnection = Event::OR;
149 
150  event->playerBitmap = 0;
151  for ( int i = 0; i < playerlistbox->GetWidgetCount(); ++i ) {
152  PG_ListBoxBaseItem* bi = dynamic_cast<PG_ListBoxBaseItem*>(playerlistbox->FindWidget(i));
153  if ( bi && bi->IsSelected() )
154  event->playerBitmap |= 1 << i;
155  }
156 
157  result = true;
158  QuitModal();
159 
160  return true;
161  }
162 
163  public:
164  EventEditor( GameMap* actmap, Event* event ) : ASC_PG_Dialog( NULL, PG_Rect( -1, -1, 700, 500 ), "Edit Event" ), result(false), gamemap(actmap)
165  {
166  this->event = event;
167 
168  int labelWidth = 80;
169  int ypos = 30;
170 
171  new PG_Label( this, PG_Rect( 10, ypos, labelWidth, 25 ), "Action:" );
172 
173  triggerNames = eventTriggerFactory::Instance().getNames();
174  actionNames = eventActionFactory::Instance().getNames();
175 
176  eventType = new DropDownSelector( this, PG_Rect( labelWidth+30, ypos, 300, 25 ), actionNames );
177  if ( event->action )
178  for ( int i = 0; i < actionNames.size(); ++i )
179  if ( event->action->getName() == actionNames[i] )
180  eventType->SelectItem ( i );
181 
182  eventType->selectionSignal.connect( sigc::mem_fun( *this, &EventEditor::actionSelected ));
183  (new PG_Button( this, PG_Rect( labelWidth + 50 + 300, ypos, 100, 25 ), "setup"))->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventEditor::setupEvent )));
184  ypos += 40;
185 
186  new PG_Label( this, PG_Rect( 10, ypos, labelWidth, 25 ), "Description:" );
187  description = new PG_LineEdit( this, PG_Rect( labelWidth+30, ypos, 420, 25 ) );
188  description->SetText( event->description );
189  ypos += 40;
190 
191  for ( int e = 0; e < 4; ++e ) {
192  new PG_Label( this, PG_Rect( 10, ypos, labelWidth, 25), "Trigger " + ASCString::toString(e));
193 
194  DropDownSelector* trigger = new DropDownSelector( this, PG_Rect( labelWidth+30, ypos, 200,25 ), triggerNames );
195 
196  (new PG_Button( this, PG_Rect( labelWidth+50+200, ypos, 100, 25 ), "setup"))->sigClick.connect( sigc::bind( sigc::mem_fun( *this, &EventEditor::setupTrigger ), e));
197 
198  PG_CheckButton* inv = new PG_CheckButton( this, PG_Rect( labelWidth+70+300, ypos, 100, 25 ), "invert");
199  inv->sigClick.connect( sigc::bind( sigc::mem_fun( *this, &EventEditor::invertTrigger ), e));
200  if ( event->trigger.size() > e ) {
201  if ( event->trigger[e]->invert )
202  inv->SetPressed();
203 
204  for ( int i = 0; i < triggerNames.size(); ++i )
205  if ( event->trigger[e]->getTypeName() == triggerNames[i] )
206  trigger->SelectItem ( i );
207  } else
208  for ( int i = 0; i < triggerNames.size(); ++i )
209  if ( triggerNames[i] == "Nothing (always false)" )
210  trigger->SelectItem ( i );
211 
212  trigger->selectionSignal.connect( sigc::bind( sigc::mem_fun( *this, &EventEditor::triggerSelected), e ));
213  ypos += 40;
214  }
215 
216  new PG_Label( this, PG_Rect( 10, ypos, labelWidth, 25 ), "Players:" );
217  playerlistbox = (new MultiListBox( this, PG_Rect( labelWidth+30, ypos, 150, 160 )))->getListBox();
218  for ( int i = 0; i < event->getMap()->getPlayerCount(); ++i ) {
219  PG_ListBoxItem* item;
220  if ( gamemap->player[i].exist() )
221  item = new PG_ListBoxItem( playerlistbox, 20, event->getMap()->player[i].getName() );
222  else
223  item = new PG_ListBoxItem( playerlistbox, 20, "inactive player " + ASCString::toString(i) );
224 
225  if ( event->playerBitmap & (1 << i))
226  item->Select();
227  }
228 
229  properties = new PG_PropertyEditor( this, PG_Rect( labelWidth + 80 + 160, ypos, 150, 160 ));
230  new PG_PropertyField_Integer<int>( properties, "Rearm Num", &event->reArmNum );
231  new PG_PropertyField_Integer<int>( properties, "Offset Turn", &event->delayedexecution.turn );
232  new PG_PropertyField_Integer<int>( properties, "Offset Move", &event->delayedexecution.move );
233  ypos += 200;
234 
235 
236  new PG_Label( this, PG_Rect( 10, ypos, labelWidth, 25 ), "Logic:" );
237  static const char* connectionNames[2] = {"all trigger must be triggered", "only one trigger must be triggered" };
238  triggerConnection = new DropDownSelector( this, PG_Rect( labelWidth+30, ypos, 300, 25 ), 2, connectionNames );
239  if ( event->triggerConnection == Event::AND )
240  triggerConnection->SelectItem( 0 );
241  else
242  triggerConnection->SelectItem( 1 );
243  ypos += 40;
244 
245 
246  AddStandardButton ( "Cancel" )->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventEditor::QuitModal )));
247  AddStandardButton ( "OK" )->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventEditor::ok )));
248 
249  };
250 
251  bool GetResult()
252  {
253  return result;
254  }
255 };
256 
257 
258 
259 
260 
261 bool createevent( GameMap* gamemap, Event* event )
262 {
263  EventEditor ee ( gamemap, event );
264  ee.Show();
265  ee.RunModal();
266  return ee.GetResult();
267 }
268 
269 // �S EventSel
270 
271 
272 class EventList : public ASC_PG_Dialog {
273  private:
274  GameMap* gamemap;
275 
276  bool ButtonNew()
277  {
278  Event* ev = new Event(*gamemap);
279  if ( !createevent( gamemap, ev ) ) {
280  delete ev;
281  return true;
282  }
283 
284  gamemap->events.push_back( ev );
285 
286  updateListbox();
287  return true;
288  }
289 
290  bool ButtonDelete()
291  {
292  int marked = listbox->GetSelectedIndex();
293  if ( marked < 0 )
294  return false;
295 
296  GameMap::Events::iterator e = gamemap->events.begin();
297  for ( int t = 0; t < marked && e != gamemap->events.end(); t++ )
298  ++e;
299 
300  if ( e != gamemap->events.end() ) {
301  delete *e;
302  gamemap->events.erase ( e );
303  updateListbox();
304  }
305 
306  return true;
307  }
308 
309  bool ButtonEdit()
310  {
311  if ( gamemap->events.size() ) {
313 
314 
315  int marked = listbox->GetSelectedIndex();
316  if ( marked < 0 )
317  return false;
318 
319  GameMap::Events::iterator e = gamemap->events.begin();
320  for ( int t = 0; t < marked && e != gamemap->events.end(); t++ )
321  ++e;
322 
323  {
324  MemoryStream stream ( &buf, tnstream::writing );
325  (*e)->write ( stream );
326  }
327 
328  if ( ! createevent( gamemap, *e ) ) {
329  // cancel pressed, we are restoring the original event
330  MemoryStream stream ( &buf, tnstream::reading );
331  (*e)->read ( stream );
332  }
333 
334  updateListbox();
335  return true;
336  } else
337  return false;
338 
339  }
340 
341  bool ButtonOK()
342  {
343  QuitModal();
344  return true;
345  }
346 
347  PG_ListBox* listbox;
348 
349 
350  void updateListbox()
351  {
352  listbox->DeleteAll();
353  for ( GameMap::Events::iterator i = gamemap->events.begin(); i != gamemap->events.end(); ++i ) {
354  ASCString text = (*i)->action->getName();
355  text += " - " + (*i)->description;
356 
357  new PG_ListBoxItem( listbox, 20, text );
358  }
359  listbox->Update();
360  }
361 
362 
363 
364  public:
365  EventList( GameMap* gameMap) : ASC_PG_Dialog( NULL, PG_Rect( -1, -1, 600, 400 ), "Edit Events" ) , gamemap ( gameMap )
366  {
367  int w = 500;
368  PG_Button* b = new PG_Button( this, PG_Rect ( w, 40, 90, 25 ), "~N~ew" );
369  b->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventList::ButtonNew )));
370 
371  b = new PG_Button( this, PG_Rect ( w, 80, 90, 25 ), "~E~dit" );
372  b->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventList::ButtonEdit )));
373 
374  b = new PG_Button( this, PG_Rect ( w, 120, 90, 25 ), "~D~elete" );
375  b->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventList::ButtonDelete )));
376 
377  b = new PG_Button( this, PG_Rect ( w, 160, 90, 25 ), "~O~K" );
378  b->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &EventList::ButtonOK )));
379 
380 
381  listbox = new PG_ListBox( this, PG_Rect( 20, 40, w - 30, Height()-50 ));
382  listbox->SetTransparency(255);
383  updateListbox();
384  };
385 
386 };
387 
388 
389 void eventEditor( GameMap* gamemap )
390 {
391  EventList te ( gamemap );
392  te.Show();
393  te.RunModal();
394 }
395 
396 
bool createevent(GameMap *gamemap, Event *event)
An in-memory storage of streamed data.
Definition: basestrm.h:172
ASCString getName() const
returns the name of the player
Definition: player.cpp:274
ASCString description
int reArmNum
the number of times this event can be executed; makes only sense in cunjunction with delayedexecution...
void warningMessage(const ASCString &str)
Events events
Definition: gamemap.h:291
virtual ASCString getName() const =0
EventAction * action
sigc::signal< void, int > selectionSignal
EventEditor(GameMap *actmap, Event *event)
The ASCString class provides an abstract way to manipulate strings.
Definition: ascstring.h:14
int resize(int top, int bottom, int left, int right)
resizes the map. Positive numbers enlarge the map in that direction
Definition: gamemap.cpp:1636
static ASCString toString(int i)
converts the parameter to a String
Definition: ascstring.cpp:193
int playerBitmap
EventList(GameMap *gameMap)
Adapter class for using Paragui Dialogs in ASC. This class transfers the event control from ASC to Pa...
Definition: paradialog.h:127
Reads data from or writes data to a MemoryStreamStorage This allows a completely volatile storage of ...
Definition: basestrm.h:204
struct Event::Delayedexecution delayedexecution
bool GetResult()
Player player[9]
Definition: gamemap.h:253
const GameMap * getMap() const
int EventActionID
EventActionID getActionID()
GameMap * actmap
Definition: spfst.cpp:64
void eventEditor(GameMap *gamemap)
Trigger trigger
enum Event::TriggerConnection triggerConnection
PG_Button * AddStandardButton(const ASCString &name)
Definition: paradialog.cpp:516
bool exist() const
does the player exist at all
Definition: player.cpp:313
The map. THE central structure of ASC, which holds everything not globally available together...
Definition: gamemap.h:182
int EventTriggerID