Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/presentation/src/world_entities/weapons/weapon_manager.cc @ 10767

Last change on this file since 10767 was 10759, checked in by bknecht, 17 years ago

hud updated

File size: 17.7 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific
12   main-programmer: Patrick Boenzli
13   co-programmer: Benjamin Grauer
14
15   2005-07-24: Benjamin Grauer: restructurate, so it can handle the new Weapons.
16   2007-01-28: Patrick Boenzli: loadable slots
17*/
18
19#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WEAPON
20
21#include "weapon_manager.h"
22#include "weapon.h"
23#include "weapon_slot.h"
24#include "crosshair.h"
25
26#include "playable.h"
27
28#include "util/loading/load_param_xml.h"
29#include "util/loading/factory.h"
30
31#include "t_animation.h"
32
33
34ObjectListDefinition(WeaponManager);
35/**
36 * @brief this initializes the weaponManager for a given nnumber of weapon slots
37 * @param number of weapon slots of the model/ship <= 10 (limitied)
38 */
39WeaponManager::WeaponManager(WorldEntity* parent)
40{
41  this->init();
42  this->setParentEntity(parent);
43
44  assert (parent != NULL);
45}
46
47WeaponManager::WeaponManager(const TiXmlElement* root)
48{
49  this->init();
50  this->loadParams(root);
51}
52
53/**
54 * @brief Destroys a WeaponManager
55 */
56WeaponManager::~WeaponManager()
57{
58  // crosshair being a PNode it must not be deleted (this is because PNodes delete themselves.)
59  // rennerc: crosshair seems not to delete itselve
60  //if (Crosshair::objectList().exists(this->crosshair))
61  //  delete this->crosshair;
62}
63
64/**
65 * @brief initializes the WeaponManager
66 */
67void WeaponManager::init()
68{
69  this->registerObject(this, WeaponManager::_objectList);
70
71  this->parentNode = NULL;
72  this->parentEntity = NULL;
73
74  for (int i = 0; i < WM_MAX_CONFIGS; i++)
75    for (int j = 0; j < WM_MAX_SLOTS; j++)
76      this->configs[i][j] = NULL;
77
78  for (int i = 0; i < WM_MAX_SLOTS; i++)
79  {
80    this->currentSlotConfig[i] = new WeaponSlot();
81    this->currentSlotConfig[i]->setCapability(WTYPE_ALL);
82    this->currentSlotConfig[i]->setCurrentWeapon(NULL);
83    this->currentSlotConfig[i]->setNextWeapon(NULL);
84
85    // NAMING
86    char* tmpName;
87    if (!this->getName().empty())
88    {
89      tmpName = new char[this->getName().size() + 10];
90      sprintf(tmpName, "%s_slot%d", this->getCName(), i);
91    }
92    else
93    {
94      tmpName = new char[30];
95      sprintf(tmpName, "WeaponMan_slot%d", i);
96    }
97    this->currentSlotConfig[i]->setName(tmpName);
98    this->currentSlotConfig[i]->deactivateNode();
99    delete[] tmpName;
100  }
101
102  for (int i = 0; i < WM_MAX_LOADED_WEAPONS; i++)
103    this->availiableWeapons[i] = NULL;
104
105
106  this->currentConfigID = 0;
107  this->slotCount = WM_MAX_SLOTS;
108  //this->weaponChange;
109
110  // CROSSHAIR INITIALISATION
111  this->crosshair = new Crosshair();
112  //this->crosshair->setRelCoor(1000,0,0);
113  this->crossHairSizeAnim = new tAnimation<Crosshair>(this->crosshair, &Crosshair::setSize);
114  this->crossHairSizeAnim->setInfinity(ANIM_INF_REWIND);
115  this->crossHairSizeAnim->addKeyFrame(50, .1, ANIM_LINEAR);
116  this->crossHairSizeAnim->addKeyFrame(100, .05, ANIM_LINEAR);
117  this->crossHairSizeAnim->addKeyFrame(50, .01, ANIM_LINEAR);
118
119  this->hideCrosshair();
120
121  this->bFire = false;
122}
123
124void WeaponManager::showCrosshair()
125{
126  if (this->crosshair)
127        this->crosshair->setVisibility( true);
128}
129
130void WeaponManager::hideCrosshair()
131{
132  if (this->crosshair)
133        this->crosshair->setVisibility( false);
134}
135
136void WeaponManager::setRotationSpeed(float speed)
137{
138  this->crosshair->setRotationSpeed(speed);
139}
140
141/**
142 * @brief loads the settings of the WeaponManager
143 * @param root the XML-element to load from
144 */
145void WeaponManager::loadParams(const TiXmlElement* root)
146{
147  BaseObject::loadParams(root);
148
149  LoadParam(root, "slotCount", this, WeaponManager, setSlotCount)
150  .describe("how many slots(cannons) the WeaponManager can handle");
151
152
153  LOAD_PARAM_START_CYCLE(root, element);
154  {
155    // CHECK IF THIS WORKS....
156    LoadParamXML_CYCLE(element, "weapons", this, WeaponManager, loadWeapons)
157    .describe("loads Weapons");
158  }
159  LOAD_PARAM_END_CYCLE(element);
160
161
162}
163
164/**
165 * @brief loads a Weapon onto the WeaponManager
166 * @param root the XML-element to load the Weapons from
167 */
168void WeaponManager::loadWeapons(const TiXmlElement* root)
169{
170  LOAD_PARAM_START_CYCLE(root, element);
171
172  BaseObject* object = Factory::fabricate(element);
173  if (object != NULL)
174  {
175    Weapon* newWeapon = dynamic_cast<Weapon*>(object);
176    if (newWeapon == NULL)
177      delete object;
178  }
179  LOAD_PARAM_END_CYCLE(element);
180}
181
182/**
183 * @brief sets the Parent of the WeaponManager.
184 * @param parent the parent of the WeaponManager
185 *
186 * this is used, to identify to which ship/man/whatever this WeaponManager is connected.
187 * also all the Slots will be subconnected to this parent.
188 *
189 * The reason this function exists is that the WeaponManager is neither a WorldEntity nor
190 * a PNode.
191 */
192void WeaponManager::setParentEntity(WorldEntity* parent)
193{
194  this->parentEntity = parent;
195  if (this->parentNode == NULL)
196    this->setParentNode(parent);
197}
198
199
200void WeaponManager::setParentNode(PNode* parent)
201{
202  this->parentNode = parent;
203  assert(parent != NULL);
204
205  if (this->parentNode != NULL)
206  {
207    for (int i = 0; i < WM_MAX_SLOTS; i++)
208      this->parentNode->addChild(this->currentSlotConfig[i]);
209  }
210
211}
212
213
214/**
215 * @brief sets the number of Slots the WeaponManager has
216 * @param slotCount the number of slots
217 */
218void WeaponManager::setSlotCount(unsigned int slotCount)
219{
220  if (slotCount <= WM_MAX_SLOTS)
221    this->slotCount = slotCount;
222  else
223    this->slotCount = WM_MAX_SLOTS;
224}
225
226
227/**
228 * @brief sets the position of the Slot relative to the parent
229 * @param slot the slot to set-up
230 * @param position the position of the given slot
231 */
232void WeaponManager::setSlotPosition(int slot, const Vector& position, PNode* parent)
233{
234  if (slot < this->slotCount)
235  {
236    this->currentSlotConfig[slot]->setRelCoor(position);
237
238    if (parent != NULL)
239      this->currentSlotConfig[slot]->setParent(parent);
240  }
241}
242
243
244/**
245 * @brief sets the relative rotation of the slot to its parent
246 * @param slot the slot to set-up
247 * @param rotation the relative rotation of the given slot
248 */
249void WeaponManager::setSlotDirection(int slot, const Quaternion& rotation)
250{
251  if (slot < this->slotCount)
252    this->currentSlotConfig[slot]->setRelDir(rotation);
253}
254
255
256/**
257 * @brief adds a weapon to the selected weaponconfiguration into the selected slot
258 * @param weapon the weapon to add
259 * @param configID an identifier for the slot: number between 0..7 if not specified: slotID=next free slot
260 * @param slotID an identifier for the weapon configuration, number between 0..3
261 *
262 * if you add explicitly a weapon at config:n, slot:m, the weapon placed at this location will be
263 * replaced by the weapon specified. if you use the WM_FREE_SLOT, the manager will look for a free
264 * slot in this weaponconfiguration. if there is non, the weapon won't be added and there will be
265 * a error message.
266 */
267bool WeaponManager::addWeapon(Weapon* weapon, int configID, int slotID)
268{
269  if ( weapon == NULL )
270    return false;
271 
272  weapon->toList( this->parentEntity->getOMListNumber() );
273
274  if (unlikely(configID >= WM_MAX_CONFIGS || slotID >= (int)this->slotCount))
275  {
276    PRINTF(2)("Slot %d of config %d is not availiabe (max: %d) searching for suitable slot\n", slotID, configID, this->slotCount);
277    if (configID >= WM_MAX_CONFIGS)
278      configID = -1;
279    if (slotID >= (int)this->slotCount)
280      slotID = -1;
281  }
282  // if no ConfigID is supplied set to Current Config.
283  if (configID <= -1)
284    configID = this->currentConfigID;
285  //
286  if (configID > -1 && slotID == -1)
287  {
288    slotID = this->getNextFreeSlot(configID, weapon->getCapability());
289    if (slotID == -1)
290      configID = -1;
291  }
292
293  if (configID > 0 && slotID > 0 && this->configs[configID][slotID] != NULL)
294  {
295    PRINTF(3)("Weapon-slot %d/%d of %s already poulated, remove weapon (%s::%s) first\n", configID, slotID, this->getCName(), weapon->getClassCName(), weapon->getCName());
296    return false;
297  }
298
299  if (slotID <= -1) // WM_FREE_SLOT
300  {
301    slotID = this->getNextFreeSlot(configID, weapon->getCapability());
302    if( slotID < 0 || slotID >= this->slotCount)
303    {
304      PRINTF(1)("There is no free slot in this WeaponConfig to dock this weapon at! Aborting\n");
305      return false;
306    }
307  }
308
309  if (!(this->currentSlotConfig[slotID]->getCapability() & weapon->getCapability() & WTYPE_ALLKINDS) &&
310      this->currentSlotConfig[slotID]->getCapability() & weapon->getCapability() & WTYPE_ALLDIRS)
311  {
312    PRINTF(2)("Unable to add Weapon with wrong capatibility to Slot %d (W:%d M:%d)\n",
313              slotID, weapon->getCapability(), this->currentSlotConfig[slotID]->getCapability());
314    return false;
315  }
316
317  //! @todo check if the weapon is already assigned to another config in another slot
318  if (this->configs[configID][slotID] != NULL)
319    return false;
320
321  this->configs[configID][slotID] = weapon;
322  weapon->setAmmoContainer(this->getAmmoContainer(weapon->getProjectileType()));
323  if(configID == this->currentConfigID)
324    this->currentSlotConfig[slotID]->setNextWeapon(weapon);
325  //if (this->parent != NULL)
326  {
327    this->parentNode->addChild(weapon);
328    if (this->parentEntity->isA(Playable::staticClassID()))
329      dynamic_cast<Playable*>(this->parentEntity)->weaponConfigChanged();
330
331    weapon->setDefaultTarget(this->crosshair);
332  }
333  PRINTF(4)("Added a new Weapon (%s::%s) to the WeaponManager: config %i/ slot %i\n", weapon->getClassCName(), weapon->getCName(), configID, slotID);
334  return true;
335}
336
337/**
338 * @brief increases the Energy of the WeaponContainer of type (projectileType)
339 * @param projectileType the type of weapon to increase Energy from
340 * @param ammo the ammo to increase
341 */
342float WeaponManager::increaseAmmunition(const ClassID& projectileType, float ammo)
343{
344  return this->getAmmoContainer(projectileType)->increaseEnergy(ammo);
345}
346
347/**
348 * @brief does the same as the funtion increaseAmmunition, added four your convenience
349 * @param weapon, the Weapon to read the ammo-info about.
350 * @param ammo how much ammo to add.
351 */
352float WeaponManager::increaseAmmunition(const Weapon* weapon, float ammo)
353{
354  assert (weapon != NULL);
355  return this->increaseAmmunition(weapon->getClassID(), ammo);
356
357}
358
359
360/**
361 * sets the capabilities of a Slot
362 * @param slot the slot to set the capability
363 * @param slotCapability the capability @see WeaponSlotCapability
364 */
365void WeaponManager::setSlotCapability(int slot, unsigned long slotCapability)
366{
367  if (slot > slotCount)
368    return;
369  this->currentSlotConfig[slot]->setCapability(slotCapability);
370}
371
372
373/**
374 * removes a Weapon from the WeaponManager
375 *
376 * !! The weapon must be inactive before you can delete it,    !!
377 * !! because it will still be deactivated (if it is selected) !!
378 */
379void WeaponManager::removeWeapon(Weapon* weapon, int configID)
380{
381  if (weapon == NULL)
382    return;
383  if (configID < 0)
384  {
385    for (int j = 0; j < WM_MAX_SLOTS; j++)
386    {
387      for (int i = 0; i < WM_MAX_CONFIGS; i++)
388      {
389        if (this->configs[i][j] == weapon)
390          this->configs[i][j] = NULL;
391      }
392      if (this->currentSlotConfig[j]->getCurrentWeapon() == weapon)
393      {
394        this->currentSlotConfig[j]->setNextWeapon(NULL);
395      }
396    }
397  }
398}
399
400
401/**
402 * changes to the next weapon configuration
403 */
404void WeaponManager::nextWeaponConfig()
405{
406  ++this->currentConfigID;
407  if (this->currentConfigID >= WM_MAX_CONFIGS)
408    this->currentConfigID = 0;
409  this->changeWeaponConfig(this->currentConfigID);
410}
411
412/**
413 * changes to the previous configuration
414 */
415void WeaponManager::previousWeaponConfig()
416{
417  --this->currentConfigID;
418  if (this->currentConfigID < 0)
419    this->currentConfigID = WM_MAX_CONFIGS -1;
420  this->changeWeaponConfig(this->currentConfigID);
421}
422
423/**
424 * change to a desired configuration
425 * @param weaponConfig the configuration to jump to.
426 */
427void WeaponManager::changeWeaponConfig(int weaponConfig)
428{
429  this->currentConfigID = weaponConfig;
430  PRINTF(4)("Changing weapon configuration: to %i\n", this->currentConfigID);
431
432  for (int i = 0; i < WM_MAX_SLOTS; i++)
433    this->currentSlotConfig[i]->setNextWeapon(this->configs[currentConfigID][i]);
434}
435
436
437/**
438 * triggers fire of all weapons in the current weaponconfig
439 */
440void WeaponManager::fire()
441{
442  Weapon* firingWeapon;
443  for(int i = 0; i < this->slotCount; i++)
444  {
445//     printf("%i ", i);
446    firingWeapon = this->currentSlotConfig[i]->getCurrentWeapon();
447    if( firingWeapon != NULL)
448    {
449      if( firingWeapon->getCurrentState() == WS_SHOOTING) continue;
450      firingWeapon->requestAction(WA_SHOOT);
451    }
452  }
453//   printf("\n");
454  /*
455        this->crosshair->setRotationSpeed(500);
456        this->crossHairSizeAnim->replay();
457  */
458}
459
460/**
461 * triggers release fire of all weapons in the current weaponconfig
462 */
463void WeaponManager::releaseFire()
464{
465  Weapon* firingWeapon;
466  for(int i = 0; i < this->slotCount; i++)
467  {
468    firingWeapon = this->currentSlotConfig[i]->getCurrentWeapon();
469    if( firingWeapon != NULL)
470      firingWeapon->requestAction(WA_NONE);
471  }
472
473  /*
474  this->crosshair->setRotationSpeed(500);
475  this->crossHairSizeAnim->replay();
476  */
477}
478
479/**
480 * triggers tick of all weapons in the current weaponconfig
481 * @param second passed since last tick
482 */
483void WeaponManager::tick(float dt)
484{
485  Weapon* tickWeapon;
486
487  for(int i = 0; i < this->slotCount; i++)
488  {
489
490    //NICE LITTLE DEBUG FUNCTION
491    /*   if (this->currentSlotConfig[i]->currentWeapon != NULL || this->currentSlotConfig[i]->nextWeapon != NULL)
492      printf("%p %p\n", this->currentSlotConfig[i]->currentWeapon, this->currentSlotConfig[i]->nextWeapon);*/
493
494    // current Weapon in Slot i
495    tickWeapon = this->currentSlotConfig[i]->getCurrentWeapon();
496    // On A change (current != next)
497    if (tickWeapon != this->currentSlotConfig[i]->getNextWeapon())
498    {
499      // if a Weapon is Active in slot i, deactivate it.
500      if (tickWeapon != NULL )
501      {
502        if (tickWeapon->isActive())
503        {
504          tickWeapon->requestAction(WA_DEACTIVATE);
505          continue;
506        }
507        else
508        {
509          tickWeapon->toList(OM_NULL);
510          this->currentSlotConfig[i]->setCurrentWeapon(NULL);
511        }
512      }
513      // switching to next Weapon
514      this->currentSlotConfig[i]->setCurrentWeapon(this->currentSlotConfig[i]->getNextWeapon());
515      tickWeapon = this->currentSlotConfig[i]->getCurrentWeapon();
516
517      if (tickWeapon != NULL)
518      {
519        //if (this->parent != NULL)
520        tickWeapon->toList(this->parentEntity->getOMListNumber());
521        tickWeapon->requestAction(WA_ACTIVATE);
522        this->currentSlotConfig[i]->activateNode();
523        tickWeapon->setParent(this->currentSlotConfig[i]);
524      }
525      else
526        this->currentSlotConfig[i]->deactivateNode();
527      if (this->parentEntity != NULL && this->parentEntity->isA(Playable::staticClassID()))
528        dynamic_cast<Playable*>(this->parentEntity)->weaponConfigChanged();
529    }
530    else if (unlikely(tickWeapon != NULL && tickWeapon->getCurrentState() == WS_DEACTIVATING))
531      this->currentSlotConfig[i]->setCurrentWeapon(NULL);
532  }
533}
534
535
536/**
537 * triggers draw of all weapons in the current weaponconfig
538 */
539void WeaponManager::draw() const
540{
541  assert(false || "must not be called");
542  Weapon* drawWeapon;
543  for (int i = 0; i < this->slotCount; i++)
544  {
545    drawWeapon = this->currentSlotConfig[i]->getCurrentWeapon();
546    if( drawWeapon != NULL && drawWeapon->isVisible())
547      drawWeapon->draw();
548  }
549}
550
551
552/**
553 * private gets the next free slot in a certain weaponconfig
554 * @param the selected weaponconfig -1 if none found
555 */
556int WeaponManager::getNextFreeSlot(int configID, long capability)
557{
558  if (configID == -1)
559  {
560    for (configID = 0; configID < WM_MAX_CONFIGS; configID++)
561      for( int i = 0; i < this->slotCount; ++i)
562      {
563        if( this->configs[configID][i] == NULL &&
564            (this->currentSlotConfig[i]->getCapability() & capability & WTYPE_ALLKINDS) &&
565            (this->currentSlotConfig[i]->getCapability() & capability & WTYPE_ALLDIRS))
566          return i;
567      }
568  }
569  else
570  {
571    for( int i = 0; i < this->slotCount; ++i)
572    {
573      if( this->configs[configID][i] == NULL &&
574          (this->currentSlotConfig[i]->getCapability() & capability & WTYPE_ALLKINDS) &&
575          (this->currentSlotConfig[i]->getCapability() & capability & WTYPE_ALLDIRS))
576        return i;
577    }
578  }
579  return -1;
580}
581
582CountPointer<AmmoContainer>& WeaponManager::getAmmoContainer(const ClassID& projectileType)
583{
584  for (unsigned int i = 0; i < this->ammo.size(); i++)
585  {
586    if (this->ammo[i]->getProjectileType() == projectileType)
587      return this->ammo[i];
588  }
589  this->ammo.push_back(CountPointer<AmmoContainer>(new AmmoContainer(projectileType)));
590  return this->ammo.back();
591}
592
593CountPointer<AmmoContainer>& WeaponManager::getAmmoContainer(const Weapon* weapon)
594{
595  assert (weapon != NULL);
596  return (this->getAmmoContainer(weapon->getClassID()));
597}
598
599
600/**
601 * outputs some nice debug information about the WeaponManager
602 */
603void WeaponManager::debug() const
604{
605  PRINT(3)("WeaponManager Debug Information\n");
606  PRINT(3)("-------------------------------\n");
607  PRINT(3)("current Config is %d\n", this->currentConfigID);
608  for (int i = 0; i < WM_MAX_CONFIGS; i++)
609  {
610    PRINT(3)("Listing Weapons in Configuration %d\n", i);
611    for (int j = 0; j < WM_MAX_SLOTS; j++)
612    {
613      if (this->configs[i][j] != NULL)
614        PRINT(3)("Slot %d loaded a %s\n", j, this->configs[i][j]->getClassCName());
615    }
616  }
617}
618
619
620long WeaponManager::getSlotCapability(int slot) const
621{
622  return this->currentSlotConfig[slot]->getCapability();
623}
624
625const Vector& WeaponManager::getSlotPosition(int slot) const
626{
627  return this->currentSlotConfig[slot]->getRelCoor();
628}
629
630Weapon* WeaponManager::getWeapon(int slotID) const
631{
632  return (slotID >= 0 && slotID < this->slotCount)? this->currentSlotConfig[slotID]->getNextWeapon(): NULL;
633}
634
635/**
636 * processes the input
637 * @param event the Event coming as input
638 */
639// void WeaponManager::process(const Event &event)
640// {
641//   if  (event.type == EV_MOUSE_MOTION)
642//   {
643//     this->crosshair->process(event);
644// //     this->setAbsCoor2D(event.x, event.y);
645//   }
646// }
Note: See TracBrowser for help on using the repository browser.