Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/playability/src/world_entities/weapons/weapon_manager.cc @ 10049

Last change on this file since 10049 was 10036, checked in by nicolasc, 18 years ago

equalized energy usage of all blasters
solved the fire echo problem, by implementing the releaseFire()
other spaceships need update

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