Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/world_entities/weapons/weapon_manager.cc @ 8630

Last change on this file since 8630 was 8315, checked in by bensch, 19 years ago

trunk: fixed a nasty seg-fault, when unloading the WeaponManager

@chrigi: do not doulbe-delete :) no, you could not have known

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