Advanced Strategic Command
internalAmmoTransferDialog.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 #include <sigc++/sigc++.h>
22 #include <sstream>
23 
25 
26 // #include "../unitctrl.h"
27 #include "../containercontrols.h"
28 #include "../gameoptions.h"
29 #include "../actions/servicing.h"
30 #include "../iconrepository.h"
31 #include "../replay.h"
32 #include "../actions/internalammotransfercommand.h"
33 #include "../sg.h"
34 #include "../dialog.h"
35 
36 
42 {
43 
44  int serviceWeaponAmmoInTransfer[ weaponTypeNum ];
45  int weaponAmmo[ 16 ]; // weapon ammo when done; might need to have *AmmoInTransfer added
46  int weaponAmmoInTransfer[ 16 ];
47  int weaponAmmoTransferSlot[ 16 ];
48  std::vector<InternalAmmoTransferWidget*> widgets;
49 
50  bool weaponAmmoTransferable[ 16 ];
51  bool serviceweaponAmmoTransferable[ weaponTypeNum ];
52  int equalWeaponsTypeCounter;
53 
54  Vehicle* _vehicle;
55 
56  public:
58  bool isAmmoTransferable( int weaponID );
59  int* weaponAmmoTransferSource( int weaponID );
60  int* weaponAmmoTransferBuffer( int weaponID );
61  int getMaxAmmo( int weaponID );
62  std::string getName( int weaponID );
63 
64  void addWidget( InternalAmmoTransferWidget* widget );
65  void updateBufferTexts();
66 
67  void performTransfer();
68 };
69 
70 class InternalAmmoTransferWidget : public PG_Widget
71 {
72  PG_Slider* slider;
74  int _weaponID;
75  int* amount;
76  int* buffer;
77  PG_Label* bufferAmount;
78  PG_Label* weaponAmount;
79 
80  std::string bufferLabel;
81  std::string unitLabel;
82 
83  public:
84  InternalAmmoTransferWidget( PG_Widget* parent, const PG_Rect& pos, InternalAmmoTransferHandler* handler, int weaponID );
85 
86  bool slide( long amount );
87  bool slideEnd( long amount );
88  void updateTexts();
89 };
90 
92 {
93  _vehicle = vehicle;
94  equalWeaponsTypeCounter = 0;
95 
96  for( int i=0; i<16; i++ )
97  {
98  weaponAmmo[ i ] = vehicle->ammo[ i ];
99  weaponAmmoInTransfer[ i ] = 0;
100  weaponAmmoTransferSlot[ i ] = -1;
101  weaponAmmoTransferable[ i ] = false;
102  }
103 
104  for( int i=0; i<weaponTypeNum; i++ )
105  {
106  serviceWeaponAmmoInTransfer[ i ] = 0;
107  serviceweaponAmmoTransferable[ i ] = false;
108  }
109 
110  for( int i=0; i<vehicle->typ->weapons.count; i++ )
111  {
112  const SingleWeapon* weapon = vehicle->getWeapon( i );
113  if( weapon->canRefuel() )
114  {
115  serviceweaponAmmoTransferable[ weapon->getScalarWeaponType() ] = true;
116  weaponAmmoTransferable[ i ] = true;
117  }
118  }
119 
120  for( int i=0; i<vehicle->typ->weapons.count; i++ )
121  {
122  const SingleWeapon* weapon = vehicle->getWeapon( i );
123  if( ! weapon->canRefuel() )
124  {
125  if( serviceweaponAmmoTransferable[ weapon->getScalarWeaponType() ] )
126  {
127  weaponAmmoTransferable[ i ] = true;
128  }else
129  {
130  for( int j=0; j<i; j++ )
131  {
132  if( weapon->equals( vehicle->getWeapon( j ) ) )
133  {
134  weaponAmmoTransferable[ i ] = true;
135  weaponAmmoTransferable[ j ] = true;
136 //std::cout << "weaponAmmoTransferable: " << i << ", " << j << endl;
137 
138  if( weaponAmmoTransferSlot[ j ] == -1 )
139  {
140  weaponAmmoTransferSlot[ j ] = equalWeaponsTypeCounter;
141  equalWeaponsTypeCounter++;
142  }
143  weaponAmmoTransferSlot[ i ] = weaponAmmoTransferSlot[ j ];
144  }
145  }
146  }
147  }
148  }
149 }
150 
152 {
153  widgets.push_back( widget );
154 }
155 
157 {
158  for( int i=0; i<widgets.size(); i++ )
159  {
160  widgets.at( i ) -> updateTexts();
161  }
162 }
163 
164 
166 {
167  return weaponAmmoTransferable[ weaponID ];
168 }
169 
171 {
172  return &weaponAmmo[ weaponID ];
173 }
174 
176 {
177  return _vehicle->getWeapon( weaponID )->count;
178 }
179 
180 std::string InternalAmmoTransferHandler::getName( int weaponID )
181 {
182  return _vehicle->getWeapon( weaponID )->getName();
183 }
184 
186 {
187  if( weaponAmmoTransferSlot[ weaponID ] >= 0 )
188  {
189  return &weaponAmmoInTransfer[ weaponAmmoTransferSlot[ weaponID ] ];
190  }else
191  {
192  return &serviceWeaponAmmoInTransfer[ _vehicle->getWeapon( weaponID )->getScalarWeaponType() ];
193  }
194 }
195 
197 {
198  // zuerst die munition von speziellen waffentypen verteilen, die noch in transfer ist
199  for( int i=0; i<16; i++ )
200  {
201  if( weaponAmmoInTransfer[ i ] > 0 )
202  {
203  for( int j=0;j<16; j++ )
204  {
205  if( weaponAmmoTransferSlot[ j ] == i )
206  {
207  const SingleWeapon* weapon = _vehicle->getWeapon( j );
208  if( weaponAmmo[ j ] < weapon->count )
209  {
210  int ammoTransfer = weapon->count - weaponAmmo[ j ];
211  if( weaponAmmoInTransfer[ i ] < ammoTransfer )
212  {
213  ammoTransfer = weaponAmmoInTransfer[ i ];
214  }
215  weaponAmmo[ j ] += ammoTransfer;
216  weaponAmmoInTransfer[ i ] -= ammoTransfer;
217  }
218  }
219  }
220  }
221  }
222 
223  // dann die munition in transfer auf servicewaffen aufteilen
224  for( int i=0; i<weaponTypeNum; i++ )
225  {
226  if( serviceWeaponAmmoInTransfer[ i ] > 0 )
227  {
228  // zuerst den servicewaffen zuweisen
229  for( int j=0; j<_vehicle->typ->weapons.count; j++ )
230  {
231  const SingleWeapon* weapon = _vehicle->getWeapon( j );
232  if( weapon->getScalarWeaponType() == i )
233  {
234  if( weapon->canRefuel() )
235  {
236  if( weaponAmmo[ j ] < weapon->count )
237  {
238  int ammoTransfer = weapon->count - weaponAmmo[ j ];
239  if( serviceWeaponAmmoInTransfer[ i ] < ammoTransfer )
240  {
241  ammoTransfer = serviceWeaponAmmoInTransfer[ i ];
242  }
243  weaponAmmo[ j ] += ammoTransfer;
244  serviceWeaponAmmoInTransfer[ i ] -= ammoTransfer;
245  }
246  }
247  }
248  }
249  // ... dann den anderen waffen zuteilen
250  for( int j=0; j<_vehicle->typ->weapons.count; j++ )
251  {
252  const SingleWeapon* weapon = _vehicle->getWeapon( j );
253  if( weapon->getScalarWeaponType() == i )
254  {
255  if( ! weapon->canRefuel() )
256  {
257  if( weaponAmmo[ j ] < weapon->count )
258  {
259  int ammoTransfer = weapon->count - weaponAmmo[ j ];
260  if( serviceWeaponAmmoInTransfer[ i ] < ammoTransfer )
261  {
262  ammoTransfer = serviceWeaponAmmoInTransfer[ i ];
263  }
264  weaponAmmo[ j ] += ammoTransfer;
265  serviceWeaponAmmoInTransfer[ i ] -= ammoTransfer;
266  }
267  }
268  }
269  }
270  }
271  }
272 
273  // munition sollte jetzt im "legalen" bereich sein,
274  // und alles was im transfer war den echten waffen zugewiesen,
275  // also jetzt dem fahrzeug zuweisen
276  vector<int> am;
277  for( int i=0; i<16; i++ )
278  am.push_back( weaponAmmo[i] );
279 
280  auto_ptr<InternalAmmoTransferCommand> iatc ( new InternalAmmoTransferCommand( _vehicle));
281  iatc->setAmmounts( am );
282  ActionResult res = iatc->execute( createContext( _vehicle->getMap() ));
283  if ( res.successful() )
284  iatc.release();
285  else
286  displayActionError( res );
287 
288 }
289 
290 
291 
292 InternalAmmoTransferWidget::InternalAmmoTransferWidget( PG_Widget* parent, const PG_Rect& pos, InternalAmmoTransferHandler* handler, int weaponID ) : PG_Widget( parent,pos ), slider(NULL), _weaponID( weaponID )
293 {
294  _handler = handler;
295  _handler->addWidget( this );
296  amount = _handler->weaponAmmoTransferSource( _weaponID );
297  buffer = _handler->weaponAmmoTransferBuffer( _weaponID );
298  bufferLabel = "Buffer ";
299  unitLabel = "Unit ";
300 
301  slider = new PG_Slider( this, PG_Rect( 0, 25, pos.w, 15 ), PG_ScrollBar::HORIZONTAL );
302  slider->SetRange( 0, _handler->getMaxAmmo( weaponID ) );
303  slider->SetPosition( *amount );
304 
305  slider->sigSlide.connect( sigc::mem_fun( *this, &InternalAmmoTransferWidget::slide ));
306  slider->sigSlideEnd.connect( sigc::mem_fun( *this, &InternalAmmoTransferWidget::slideEnd));
307 
308  PG_Rect labels = PG_Rect( 0, 0, pos.w, 20 );
309  std::stringstream nameStream;
310  nameStream << handler->getName( weaponID ) << " (" << weaponID << ")";
311  PG_Label* l = new PG_Label ( this, labels, nameStream.str() );
312  l->SetAlignment( PG_Label::CENTER );
313 
314  bufferAmount = new PG_Label ( this, labels );
315  bufferAmount->SetAlignment( PG_Label::LEFT );
316 
317  weaponAmount = new PG_Label ( this, labels );
318  weaponAmount->SetAlignment( PG_Label::RIGHT );
319 
320  updateTexts();
321 }
322 
323 
324 bool InternalAmmoTransferWidget::slide( long newAmount )
325 {
326  int difference = newAmount - (*amount);
327  if( difference > (*buffer) )
328  {
329  difference = (*buffer);
330  }
331  (*amount) += difference;
332  (*buffer) -= difference;
333 
334  if( difference != 0 )
335  {
336  _handler->updateBufferTexts();
337  return true;
338  }
339  return false;
340 }
341 
343 {
344  std::stringstream ssStream;
345  ssStream << bufferLabel << (*buffer);
346  bufferAmount->SetText( ssStream.str() );
347 
348  std::stringstream ssStream2;
349  ssStream2 << unitLabel << (*amount);
350  weaponAmount->SetText( ssStream2.str() );
351 }
352 
354 {
355  int difference = newAmount - (*amount);
356  if( difference > (*buffer) )
357  {
358  difference = (*buffer);
359  }
360  (*amount) += difference;
361  (*buffer) -= difference;
362 
363  if( difference != 0 )
364  {
365  _handler->updateBufferTexts();
366  return true;
367  }
368  return false;
369 }
370 
371 
373  private:
374  Vehicle* vehicle;
376  //ContainerBase* second;
377  //TransferHandler handler;
378 
379 
380  Surface img1,img2;
381 
382  bool ok()
383  {
384  handler.performTransfer();
385  QuitModal();
386  return true;
387  }
388 
389  public:
390  InternalAmmoTransferWindow ( Vehicle* source, PG_Widget* parent );
391 
393 
394  bool eventKeyDown(const SDL_KeyboardEvent* key)
395  {
396  if ( key->keysym.sym == SDLK_ESCAPE ) {
397  QuitModal();
398  return true;
399  }
400  return false;
401  }
402 
403 
404 };
405 
406 
407 InternalAmmoTransferWindow :: InternalAmmoTransferWindow ( Vehicle* source, PG_Widget* parent ) : ASC_PG_Dialog( NULL, PG_Rect( 30, 30, 400, 400 ), "Transfer" ), vehicle( source ), handler( source )//, second( destination ), handler( source, destination )
408 {
409  int ypos = 30;
410  int border = 10;
411 
412  img1 = IconRepository::getIcon( "container.png" );//source->getImage();
413  img2 = source->getImage();
414 
415  const int singleTransferHeight = 60;
416 
417  int transferableWeaponsCounter = 0;
418 
419  for( int i=0; i<16; i++ )
420  {
421  if( handler.isAmmoTransferable( i ) ) transferableWeaponsCounter++;
422  }
423 
424  int expectedHeight = transferableWeaponsCounter * singleTransferHeight;
425 
426  int newHeight = min( PG_Application::GetScreen()->h - 60, expectedHeight + 130 );
427  SizeWidget( w, newHeight );
428 
429  PG_ScrollWidget* area = new PG_ScrollWidget ( this, PG_Rect( border, ypos, w - border, h - 80 ));
430  area->SetTransparency( 255 );
431 
432  (new PG_ThemeWidget( area, PG_Rect( 5,3, fieldsizex, fieldsizey)))->SetBackground( img1.getBaseSurface(), PG_Draw::STRETCH );
433  (new PG_ThemeWidget( area, PG_Rect( area->Width() - 5 - fieldsizex, 3, fieldsizex, fieldsizey)))->SetBackground( img2.getBaseSurface(), PG_Draw::STRETCH );
434 
435  ypos = fieldsizex + 5;
436 
437  for( int i=0; i<16; i++ )
438  {
439  if( handler.isAmmoTransferable( i ) )
440  {
441  new InternalAmmoTransferWidget( area, PG_Rect( 0, ypos, area->w - 30, 50 ), &handler, i );
442  ypos += singleTransferHeight;
443  }
444  }
445 
446  int buttonWidth = 150;
447  PG_Button* b = new PG_Button( this, PG_Rect( w - buttonWidth - border, h - 30 - border, buttonWidth, 30), "OK" );
448  b->sigClick.connect( sigc::hide( sigc::mem_fun( *this, &InternalAmmoTransferWindow::ok )));
449 }
450 
452 {
453  InternalAmmoTransferWindow iatw( vehicle, NULL );
454  if ( iatw.somethingToTransfer() ) {
455  iatw.Show();
456  iatw.RunModal();
457  }
458 }
bool eventKeyDown(const SDL_KeyboardEvent *key)
ASCString getName(void) const
#define weaponTypeNum
Definition: vehicletype.h:63
int ammo[16]
Definition: vehicle.h:87
UnitWeapon weapons
The weapons.
Definition: vehicletype.h:248
Context createContext(GameMap *gamemap)
bool canRefuel(void) const
void internalAmmoTransferWindow(Vehicle *vehicle)
int count
amount of ammunition the unit having this weapon can carry
Definition: vehicletype.h:117
SDL_Surface * getBaseSurface()
Definition: surface.h:116
virtual Surface getImage() const
returns an image for the Container.
Definition: vehicle.cpp:1706
#define fieldsizey
Definition: typen.h:441
int getScalarWeaponType(void) const
void addWidget(InternalAmmoTransferWidget *widget)
Adapter class for using Paragui Dialogs in ASC. This class transfers the event control from ASC to Pa...
Definition: paradialog.h:127
static bool avail(const Vehicle *unit)
A single weapon of a #Vehicletype.
Definition: vehicletype.h:100
InternalAmmoTransferWindow(Vehicle *source, PG_Widget *parent)
#define fieldsizex
Definition: typen.h:440
bool successful() const
InternalAmmoTransferWidget(PG_Widget *parent, const PG_Rect &pos, InternalAmmoTransferHandler *handler, int weaponID)
bool equals(const SingleWeapon *otherWeapon) const
const VehicleType * typ
Definition: vehicle.h:83
static Surface & getIcon(const ASCString &name)
GameMap * getMap() const
const T & min(const T &a, const T &b, const T &c)
Definition: misc.h:80
void displayActionError(const ActionResult &result, const ASCString &additionalInfo)
Definition: dialog.cpp:2168
const SingleWeapon * getWeapon(unsigned weaponNum) const
Returns the SingleWeapon corresponding to the weaponNum for this vehicle.
Definition: vehicle.cpp:1760