Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: Slots are now PNodes

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