Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: flush

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