Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/world_entities/weapons/weapon.cc @ 5041

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

orxonox/trunk: less output of Weapon

File size: 16.2 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-15: Benjamin Grauer: restructurating the entire Class
17*/
18
19#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WEAPON
20
21#include "weapon.h"
22
23#include "projectile.h"
24
25#include "class_list.h"
26#include "load_param.h"
27#include "state.h"
28#include "sound_engine.h"
29#include "animation3d.h"
30#include "vector.h"
31
32////////////////////
33// INITAILISATION //
34// SETTING VALUES //
35////////////////////
36/**
37 * standard constructor
38 *
39 * creates a new weapon
40*/
41Weapon::Weapon (WeaponManager* weaponManager)
42{
43  this->init();
44  this->setWeaponManager(weaponManager);
45}
46
47/**
48 * standard deconstructor
49*/
50Weapon::~Weapon ()
51{
52  for (int i = 0; i < WS_STATE_COUNT; i++)
53    if (this->animation[i] && ClassList::exists(animation[i], CL_ANIMATION))  //!< @todo this should check animation3D
54      delete this->animation[i];
55  for (int i = 0; i < WA_ACTION_COUNT; i++)
56    if (this->soundBuffers[i])
57      ResourceManager::getInstance()->unload(this->soundBuffers[i]);
58
59  if (ClassList::exists(this->soundSource, CL_SOUND_SOURCE))
60    delete this->soundSource;
61}
62
63/**
64 * initializes the Weapon with ALL default values
65 */
66void Weapon::init()
67{
68  this->currentState     = WS_INACTIVE;
69  this->requestedAction  = WA_NONE;
70  this->stateDuration    = 0.0;
71  for (int i = 0; i < WS_STATE_COUNT; i++)
72    {
73      this->times[i] = 0.0;
74      this->animation[i] = NULL;
75    }
76  for (int i = 0; i < WA_ACTION_COUNT; i++)
77    this->soundBuffers[i] = NULL;
78
79  this->soundSource = new SoundSource(this);
80  this->emissionPoint.setParent(this);
81
82  this->projectile = CL_NULL;
83  this->projectileFactory = NULL;
84
85  this->hideInactive = true;
86
87  this->minCharge = 1.0;
88  this->maxCharge = 1.0;
89
90  this->energyLoaded = .0;
91  this->energyLoadedMax = 5.0;
92  this->energy = .0;
93  this->energyMax = 10.0;
94
95  this->setWeaponManager(NULL);
96}
97
98void Weapon::loadParams(const TiXmlElement* root)
99{
100  static_cast<WorldEntity*>(this)->loadParams(root);
101
102  LoadParam<Weapon>(root, "projectile", this, &Weapon::setProjectile)
103      .describe("Sets the name of the Projectile to load onto the Entity");
104
105  LoadParam<Weapon>(root, "emission-point", this, &Weapon::setEmissionPoint)
106      .describe("Sets the Point of emission of this weapon");
107
108  LoadParam<Weapon>(root, "state-duration", this, &Weapon::setStateDuration)
109      .describe("Sets the duration of a given state (1: state-Name; 2: duration in seconds)");
110
111  LoadParam<Weapon>(root, "action-sound", this, &Weapon::setActionSound)
112      .describe("Sets a given sound to an action (1: action-Name; 2: name of the sound (relative to the Data-Path))");
113}
114
115/**
116 * sets the Projectile to use for this weapon.
117 * @param projectile The ID of the Projectile to use
118 * @returns true, if it was sucessfull, false on error
119 *
120 * be aware, that this function does not create Factories, as this is job of Bullet-classes.
121 */
122void Weapon::setProjectile(ClassID projectile)
123{
124  if (projectile == CL_NULL)
125    return;
126  this->projectile = projectile;
127  this->projectileFactory = FastFactory::searchFastFactory(projectile);
128  if (this->projectileFactory == NULL)
129  {
130    PRINTF(1)("unable to find FastFactory for the Projectile.\n");
131    return;
132  }
133  else
134  {
135    // grabbing Parameters from the Projectile to have them at hand here.
136    Projectile* pj = dynamic_cast<Projectile*>(this->projectileFactory->resurrect());
137    this->minCharge = pj->getEnergyMin();
138    this->maxCharge = pj->getEnergyMax();
139    this->chargeable = pj->isChageable();
140    this->projectileFactory->kill(pj);
141  }
142}
143
144/**
145 * @see bool Weapon::setProjectile(ClassID projectile)
146 * @param projectile the Name of the Projectile.
147 */
148void Weapon::setProjectile(const char* projectile)
149{
150  if (projectile == NULL)
151    return;
152  FastFactory* tmpFac = FastFactory::searchFastFactory(projectile);
153  if (tmpFac != NULL)
154  {
155    this->setProjectile(tmpFac->getStoredID());
156  }
157  else
158  {
159    PRINTF(2)("Projectile %s does not exist for weapon %s\n", projectile, this->getName());
160  }
161}
162
163/**
164 * sets the emissionPoint's relative position from the Weapon
165 * @param point the Point relative to the mass-point of the Weapon
166 */
167void Weapon::setEmissionPoint(const Vector& point)
168{
169  this->emissionPoint.setRelCoor(point);
170}
171
172/**
173 * assigns a Sound-file to an action
174 * @param action the action the sound should be assigned too
175 * @param soundFile the soundFile's relative position to the data-directory (will be looked for by the ResourceManager)
176 */
177void Weapon::setActionSound(WeaponAction action, const char* soundFile)
178{
179  if (action >= WA_ACTION_COUNT)
180    return;
181  if (this->soundBuffers[action] != NULL)
182    ResourceManager::getInstance()->unload(this->soundBuffers[action]);
183
184  else if (soundFile != NULL)
185  {
186    this->soundBuffers[action] = (SoundBuffer*)ResourceManager::getInstance()->load(soundFile, WAV);
187    if (this->soundBuffers[action] != NULL)
188    {
189      PRINTF(4)("Loaded sound %s to action %s.\n", soundFile, actionToChar(action));
190    }
191    else
192    {
193      PRINTF(2)("Failed to load sound %s to %s.\n.", soundFile, actionToChar(action));
194    }
195  }
196  else
197    this->soundBuffers[action] = NULL;
198}
199
200/**
201 * creates/returns an Animation3D for a certain State.
202 * @param state what State should the Animation be created/returned for
203 * @param node the node this Animation should apply to. (NULL is fine if the animation was already created)
204 * @returns The created animation.Animation(), NULL on error (or if the animation does not yet exist).
205 *
206 * This function does only generate the Animation Object, and if set it will
207 * automatically be executed, when a certain State is reached.
208 * What this does not do, is set keyframes, you have to operate on the returned animation.
209 */
210Animation3D* Weapon::getAnimation(WeaponState state, PNode* node)
211{
212  if (state >= WS_STATE_COUNT) // if the state is not known
213    return NULL;
214
215  if (unlikely(this->animation[state] == NULL)) // if the animation does not exist yet create it.
216  {
217    if (likely(node != NULL))
218      return this->animation[state] = new Animation3D(node);
219    else
220    {
221      PRINTF(2)("Node not defined for the Creation of the 3D-animation of state %s\n", stateToChar(state));
222      return NULL;
223    }
224  }
225  else
226    return this->animation[state];
227}
228
229/////////////////
230//  EXECUTION  //
231// GAME ACTION //
232/////////////////
233/**
234 * request an action that should be executed,
235 * @param action the next action to take
236 *
237 * This function must be called instead of the actions (like fire/reload...)
238 * to make all the checks needed to have a usefull WeaponSystem.
239 */
240void Weapon::requestAction(WeaponAction action)
241{
242  if (likely(this->isActive()))
243  {
244    if (this->requestedAction != WA_NONE)
245      return;
246    PRINTF(5)("next action will be %s in %f seconds\n", actionToChar(action), this->stateDuration);
247    this->requestedAction = action;
248  }
249  //else
250  else if (unlikely(action == WA_ACTIVATE))
251  {
252    this->currentState = WS_ACTIVATING;
253    this->requestedAction = WA_ACTIVATE;
254  }
255}
256
257/**
258 * adds energy to the Weapon
259 * @param energyToAdd The amount of energy
260 * @returns the amount of energy we did not pick up, because the weapon is already full
261 */
262float Weapon::increaseEnergy(float energyToAdd)
263{
264  float maxAddEnergy = this->energyMax - this->energy;
265
266  if (maxAddEnergy >= energyToAdd)
267  {
268    this->energy += energyToAdd;
269    return 0.0;
270  }
271  else
272  {
273    this->energy += maxAddEnergy;
274    return energyToAdd - maxAddEnergy;
275  }
276}
277
278//////////////////////
279// WEAPON INTERNALS //
280//////////////////////
281/**
282 * executes an action, and with it starts a new State.
283 * @return true, if it worked, false otherwise
284 *
285 * This function checks, wheter the possibility of executing an action is valid,
286 * and does all the necessary stuff, to execute them. If an action does not succeed,
287 * it tries to go around it. (ex. shoot->noAmo->reload()->wait until shoot comes again)
288 */
289bool Weapon::execute()
290{
291#if DEBUG > 4
292  PRINTF(4)("trying to execute action %s\n", actionToChar(this->requestedAction));
293  this->debug();
294#endif
295
296  WeaponAction action = this->requestedAction;
297  this->requestedAction = WA_NONE;
298
299  switch (action)
300  {
301    case WA_SHOOT:
302      return this->fireW();
303      break;
304    case WA_CHARGE:
305      return this->chargeW();
306      break;
307    case WA_RELOAD:
308      return this->reloadW();
309      break;
310    case WA_DEACTIVATE:
311      return this->deactivateW();
312      break;
313    case WA_ACTIVATE:
314      return this->activateW();
315      break;
316  }
317}
318
319/**
320 * checks and activates the Weapon.
321 * @return true on success.
322 */
323bool Weapon::activateW()
324{
325//  if (this->currentState == WS_INACTIVE)
326  {
327        // play Sound
328    if (likely(this->soundBuffers[WA_ACTIVATE] != NULL))
329      this->soundSource->play(this->soundBuffers[WA_ACTIVATE]);
330        // activate
331    PRINTF(4)("Activating the Weapon %s\n", this->getName());
332    this->activate();
333    // setting up for next action
334    this->enterState(WS_ACTIVATING);
335  }
336}
337
338/**
339 * checks and deactivates the Weapon
340 * @return true on success.
341 */
342bool Weapon::deactivateW()
343{
344//  if (this->currentState != WS_INACTIVE)
345  {
346    PRINTF(4)("Deactivating the Weapon %s\n", this->getName());
347        // play Sound
348    if (this->soundBuffers[WA_DEACTIVATE] != NULL)
349      this->soundSource->play(this->soundBuffers[WA_DEACTIVATE]);
350    // deactivate
351    this->deactivate();
352    this->enterState(WS_DEACTIVATING);
353  }
354}
355
356/**
357 * checks and charges the Weapon
358 * @return true on success.
359 */
360bool Weapon::chargeW()
361{
362  if ( this->currentState != WS_INACTIVE && this->energyLoaded >= this->minCharge)
363  {
364        // playing Sound
365    if (this->soundBuffers[WA_CHARGE] != NULL)
366      this->soundSource->play(this->soundBuffers[WA_CHARGE]);
367
368        // charge
369    this->charge();
370        // setting up for the next state
371    this->enterState(WS_CHARGING);
372  }
373  else // deactivate the Weapon if we do not have enough energy
374  {
375    this->requestAction(WA_RELOAD);
376  }
377}
378
379/**
380 * checks and fires the Weapon
381 * @return true on success.
382 */
383bool Weapon::fireW()
384{
385     //if (likely(this->currentState != WS_INACTIVE))
386  if (this->minCharge <= this->energyLoaded)
387  {
388          // playing Sound
389    if (this->soundBuffers[WA_SHOOT] != NULL)
390      this->soundSource->play(this->soundBuffers[WA_SHOOT]);
391          // fire
392    this->fire();
393    this->energyLoaded -= this->minCharge;
394          // setting up for the next state
395    this->enterState(WS_SHOOTING);
396  }
397  else  // reload if we still have the charge
398  {
399    this->requestAction(WA_RELOAD);
400    this->execute();
401  }
402}
403
404/**
405 * checks and Reloads the Weapon
406 * @return true on success.
407 */
408bool Weapon::reloadW()
409{
410  PRINTF(4)("Reloading Weapon %s\n", this->getName());
411  if (unlikely(this->energy + this->energyLoaded < this->minCharge))
412  {
413    this->requestAction(WA_DEACTIVATE);
414    this->execute();
415    return false;
416  }
417
418  float chargeSize = this->energyLoadedMax - this->energyLoaded;       //!< The energy to be charged
419
420  if (this->soundBuffers[WA_RELOAD] != NULL)
421    this->soundSource->play(this->soundBuffers[WA_RELOAD]);
422
423  if (chargeSize > this->energy)
424  {
425    this->energyLoaded += this->energy;
426    this->energy = 0.0;
427    PRINT(5)("Energy depleted\n");
428  }
429  else
430  {
431    PRINTF(5)("Loaded %f energy into the Guns Buffer\n", chargeSize);
432    this->energyLoaded += chargeSize;
433    this->energy -= chargeSize;
434  }
435  this->reload();
436  this->enterState(WS_RELOADING);
437}
438
439/**
440 * enters the requested State, plays back animations updates the timing.
441 * @param state the state to enter.
442 */
443inline void Weapon::enterState(WeaponState state)
444{
445  PRINTF(4)("ENTERING STATE %s\n", stateToChar(state));
446  // playing animation if availiable
447  if (likely(this->animation[state] != NULL))
448    this->animation[state]->replay();
449
450  this->stateDuration = this->times[state] + this->stateDuration;
451  this->currentState = state;
452}
453
454///////////////////
455//  WORLD-ENTITY //
456// FUNCTIONALITY //
457///////////////////
458/**
459 * tick signal for time dependent/driven stuff
460*/
461void Weapon::tickW(float dt)
462{
463  //printf("%s ", stateToChar(this->currentState));
464
465  // setting up the timing properties
466  this->stateDuration -= dt;
467
468  if (this->stateDuration <= 0.0)
469  {
470    if (unlikely (this->currentState == WS_DEACTIVATING))
471    {
472      this->currentState = WS_INACTIVE;
473      return;
474    }
475    else
476      this->currentState = WS_IDLE;
477
478    if (this->requestedAction != WA_NONE)
479    {
480      this->stateDuration = -dt;
481      this->execute();
482    }
483  }
484  tick(dt);
485}
486
487/**
488 *  this will draw the weapon
489*/
490void Weapon::draw ()
491{}
492
493
494
495
496
497//////////////////////
498// HELPER FUNCTIONS //
499//////////////////////
500/**
501 * checks wether all the Weapons functions are valid, and if it is possible to go to action with it.
502 *
503 */
504bool Weapon::check() const
505{
506  bool retVal = true;
507
508//  if (this->projectile == NULL)
509  {
510    PRINTF(1)("There was no projectile assigned to the Weapon.\n");
511    retVal = false;
512  }
513
514
515
516
517  return retVal;
518}
519
520/**
521 * some nice debugging information about this Weapon
522 */
523void Weapon::debug() const
524{
525  PRINT(3)("Weapon-Debug %s, state: %s, nextAction: %s\n", this->getName(), Weapon::stateToChar(this->currentState), Weapon::actionToChar(requestedAction));
526  PRINT(3)("Energy: max: %f; current: %f;  loadedMax: %f; loadedCurrent: %f; chargeMin: %f, chargeMax %f\n",
527            this->energyMax, this->energy, this->energyLoadedMax, this->energyLoaded, this->minCharge, this->maxCharge);
528
529
530}
531
532
533// static
534/**
535 * Converts a String into an Action.
536 * @param action the String input holding the Action.
537 * @return The Action if known, WA_NONE otherwise.
538 */
539WeaponAction Weapon::charToAction(const char* action)
540{
541  if (!strcmp(action, "none"))
542    return WA_NONE;
543  else if (!strcmp(action, "shoot"))
544    return WA_SHOOT;
545  else if (!strcmp(action, "charge"))
546    return WA_CHARGE;
547  else if (!strcmp(action, "reload"))
548    return WA_RELOAD;
549  else if (!strcmp(action, "acitvate"))
550    return WA_ACTIVATE;
551  else if (!strcmp(action, "deactivate"))
552    return WA_DEACTIVATE;
553  else if (!strcmp(action, "special1"))
554    return WA_SPECIAL1;
555  else
556    {
557      PRINTF(2)("action %s could not be identified.\n", action);
558      return WA_NONE;
559    }
560}
561
562/**
563 * converts an action into a String
564 * @param action the action to convert
565 * @return a String matching the name of the action
566 */
567const char* Weapon::actionToChar(WeaponAction action)
568{
569  switch (action)
570  {
571    case WA_SHOOT:
572      return "shoot";
573      break;
574    case WA_CHARGE:
575      return "charge";
576      break;
577    case WA_RELOAD:
578      return "reload";
579      break;
580    case WA_ACTIVATE:
581      return "activate";
582      break;
583    case WA_DEACTIVATE:
584      return "deactivate";
585      break;
586    case WA_SPECIAL1:
587      return "special1";
588      break;
589    default:
590      return "none";
591      break;
592  }
593}
594
595/**
596 * Converts a String into a State.
597 * @param state the String input holding the State.
598 * @return The State if known, WS_NONE otherwise.
599 */
600WeaponState Weapon::charToState(const char* state)
601{
602  if (!strcmp(state, "none"))
603    return WS_NONE;
604  else if (!strcmp(state, "shooting"))
605    return WS_SHOOTING;
606  else if (!strcmp(state, "charging"))
607    return WS_CHARGING;
608  else if (!strcmp(state, "reloading"))
609    return WS_RELOADING;
610  else if (!strcmp(state, "activating"))
611    return WS_ACTIVATING;
612  else if (!strcmp(state, "deactivating"))
613    return WS_DEACTIVATING;
614  else if (!strcmp(state, "inactive"))
615    return WS_INACTIVE;
616  else if (!strcmp(state, "idle"))
617    return WS_IDLE;
618  else
619    {
620      PRINTF(2)("state %s could not be identified.\n", state);
621      return WS_NONE;
622    }
623}
624
625/**
626 * converts a State into a String
627 * @param state the state to convert
628 * @return a String matching the name of the state
629 */
630const char* Weapon::stateToChar(WeaponState state)
631{
632  switch (state)
633  {
634    case WS_SHOOTING:
635      return "shooting";
636      break;
637    case WS_CHARGING:
638      return "charging";
639      break;
640    case WS_RELOADING:
641      return "reloading";
642      break;
643    case WS_ACTIVATING:
644      return "activating";
645      break;
646    case WS_DEACTIVATING:
647      return "deactivating";
648      break;
649    case WS_IDLE:
650      return "idle";
651      break;
652    case WS_INACTIVE:
653      return "inactive";
654      break;
655    default:
656      return "none";
657      break;
658  }
659}
Note: See TracBrowser for help on using the repository browser.