Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: some smaller fixes, to make Weapon more local

File size: 13.9 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->soundSource = new SoundSource(this);
80  this->emissionPoint.setParent(this);
81
82  this->projectile = NULL;
83
84  this->hideInactive = true;
85
86  this->minCharge = 1.0;
87  this->maxCharge = 1.0;
88
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->requestedAction = WA_ACTIVATE;
186  }
187}
188
189/**
190 * adds energy to the Weapon
191 * @param energyToAdd The amount of energy
192 * @returns the amount of energy we did not pick up, because the weapon is already full
193 */
194float Weapon::increaseEnergy(float energyToAdd)
195{
196  float maxAddEnergy = this->energyMax - this->energy;
197
198  if (maxAddEnergy >= energyToAdd)
199  {
200    this->energy += energyToAdd;
201    return 0.0;
202  }
203  else
204  {
205    this->energy += maxAddEnergy;
206    return energyToAdd - maxAddEnergy;
207  }
208}
209
210//////////////////////
211// WEAPON INTERNALS //
212//////////////////////
213/**
214 * executes an action, and with it starts a new State.
215 * @return true, if it worked, false otherwise
216 *
217 * This function checks, wheter the possibility of executing an action is valid,
218 * and does all the necessary stuff, to execute them. If an action does not succeed,
219 * it tries to go around it. (ex. shoot->noAmo->reload()->wait until shoot comes again)
220 */
221bool Weapon::execute()
222{
223#if DEBUG > 4
224  PRINTF(4)("trying to execute action %s\n", actionToChar(this->requestedAction));
225  this->debug();
226#endif
227
228  WeaponAction action = this->requestedAction;
229  this->requestedAction = WA_NONE;
230
231  switch (action)
232  {
233    case WA_SHOOT:
234      return this->fireW();
235      break;
236    case WA_CHARGE:
237      return this->chargeW();
238      break;
239    case WA_RELOAD:
240      return this->reloadW();
241      break;
242    case WA_DEACTIVATE:
243      return this->deactivateW();
244      break;
245    case WA_ACTIVATE:
246      return this->activateW();
247      break;
248  }
249}
250
251/**
252 * checks and activates the Weapon.
253 * @return true on success.
254 */
255bool Weapon::activateW()
256{
257//  if (this->currentState == WS_INACTIVE)
258  {
259        // play Sound
260    if (likely(this->soundBuffers[WA_ACTIVATE] != NULL))
261      this->soundSource->play(this->soundBuffers[WA_ACTIVATE]);
262        // activate
263    PRINTF(4)("Activating the Weapon %s\n", this->getName());
264    this->activate();
265    // setting up for next action
266    this->enterState(WS_ACTIVATING);
267  }
268}
269
270/**
271 * checks and deactivates the Weapon
272 * @return true on success.
273 */
274bool Weapon::deactivateW()
275{
276  if (this->currentState != WS_INACTIVE)
277  {
278    PRINTF(4)("Deactivating the Weapon %s\n", this->getName());
279        // play Sound
280    if (this->soundBuffers[WA_DEACTIVATE] != NULL)
281      this->soundSource->play(this->soundBuffers[WA_DEACTIVATE]);
282    // deactivate
283    this->deactivate();
284    this->enterState(WS_DEACTIVATING);
285  }
286}
287
288/**
289 * checks and charges the Weapon
290 * @return true on success.
291 */
292bool Weapon::chargeW()
293{
294  if ( this->currentState != WS_INACTIVE && this->energyLoaded >= this->minCharge)
295  {
296        // playing Sound
297    if (this->soundBuffers[WA_CHARGE] != NULL)
298      this->soundSource->play(this->soundBuffers[WA_CHARGE]);
299
300        // charge
301    this->charge();
302        // setting up for the next state
303    this->enterState(WS_CHARGING);
304  }
305  else // deactivate the Weapon if we do not have enough energy
306  {
307    this->requestAction(WA_RELOAD);
308  }
309}
310
311/**
312 * checks and fires the Weapon
313 * @return true on success.
314 */
315bool Weapon::fireW()
316{
317     //if (likely(this->currentState != WS_INACTIVE))
318  if (this->minCharge <= this->energyLoaded)
319  {
320          // playing Sound
321    if (this->soundBuffers[WA_SHOOT] != NULL)
322      this->soundSource->play(this->soundBuffers[WA_SHOOT]);
323          // fire
324    this->fire();
325    this->energyLoaded -= this->minCharge;
326          // setting up for the next state
327    this->enterState(WS_SHOOTING);
328  }
329  else  // reload if we still have the charge
330  {
331    this->requestAction(WA_RELOAD);
332  }
333}
334
335
336/**
337 * checks and Reloads the Weapon
338 * @return true on success.
339 */
340bool Weapon::reloadW()
341{
342  PRINTF(4)("Reloading Weapon %s\n", this->getName());
343  if (unlikely(this->energy + this->energyLoaded < this->minCharge))
344  {
345    this->requestAction(WA_DEACTIVATE);
346    return false;
347  }
348
349  float chargeSize = this->energyLoadedMax - this->energyLoaded;       //!< The energy to be charged
350
351  if (this->soundBuffers[WA_RELOAD] != NULL)
352    this->soundSource->play(this->soundBuffers[WA_RELOAD]);
353
354  if (chargeSize > this->energy)
355  {
356    this->energyLoaded += this->energy;
357    this->energy = 0.0;
358    PRINT(3)("Energy empty");
359  }
360  else
361  {
362    PRINTF(3)("Loaded %f energy into the Guns Buffer\n", chargeSize);
363    this->energyLoaded += chargeSize;
364    this->energy -= chargeSize;
365  }
366  this->reload();
367  this->enterState(WS_RELOADING);
368}
369
370/**
371 * enters the requested State, plays back animations updates the timing.
372 * @param state the state to enter.
373 */
374inline void Weapon::enterState(WeaponState state)
375{
376  // playing animation if availiable
377  if (likely(this->animation[state] != NULL))
378    this->animation[state]->replay();
379
380  this->stateDuration = this->times[state] + this->stateDuration;
381  this->currentState = state;
382}
383
384
385
386///////////////////
387//  WORLD-ENTITY //
388// FUNCTIONALITY //
389///////////////////
390/**
391 * tick signal for time dependent/driven stuff
392*/
393void Weapon::tickW(float dt)
394{
395  printf("%s ", stateToChar(this->currentState));
396
397  // setting up the timing properties
398  this->stateDuration -= dt;
399
400  if (this->isActive())
401  {
402    if (this->stateDuration <= 0.0)
403    {
404      if (unlikely (this->currentState == WS_DEACTIVATING))
405      {
406        this->currentState = WS_INACTIVE;
407        return;
408      }
409      else
410        this->currentState = WS_IDLE;
411
412      if (this->requestedAction != WA_NONE)
413      {
414        this->stateDuration = -dt;
415        this->execute();
416      }
417    }
418  }
419  tick(dt);
420}
421
422/**
423 *  this will draw the weapon
424*/
425void Weapon::draw ()
426{}
427
428
429
430
431
432//////////////////////
433// HELPER FUNCTIONS //
434//////////////////////
435/**
436 * checks wether all the Weapons functions are valid, and if it is possible to go to action with it.
437 *
438 */
439bool Weapon::check() const
440{
441  bool retVal = true;
442
443  if (this->projectile == NULL)
444  {
445    PRINTF(2)("There was no projectile assigned to the Weapon.\n");
446    retVal = false;
447  }
448
449
450
451
452  return retVal;
453}
454
455/**
456 * some nice debugging information about this Weapon
457 */
458void Weapon::debug() const
459{
460  PRINT(3)("Weapon-Debug %s, state: %s, nexAction: %s\n", this->getName(), Weapon::stateToChar(this->currentState), Weapon::actionToChar(requestedAction));
461  PRINT(3)("Energy: max: %f; current: %f;  loadedMax: %f; loadedCurrent: %f; chargeMin: %f, chargeMax %f\n",
462            this->energyMax, this->energy, this->energyLoadedMax, this->energyLoaded, this->minCharge, this->maxCharge);
463}
464
465
466// static
467/**
468 * Converts a String into an Action.
469 * @param action the String input holding the Action.
470 * @return The Action if known, WA_NONE otherwise.
471 */
472WeaponAction Weapon::charToAction(const char* action)
473{
474  if (!strcmp(action, "none"))
475    return WA_NONE;
476  else if (!strcmp(action, "shoot"))
477    return WA_SHOOT;
478  else if (!strcmp(action, "charge"))
479    return WA_CHARGE;
480  else if (!strcmp(action, "reload"))
481    return WA_RELOAD;
482  else if (!strcmp(action, "acitvate"))
483    return WA_ACTIVATE;
484  else if (!strcmp(action, "deactivate"))
485    return WA_DEACTIVATE;
486  else if (!strcmp(action, "special1"))
487    return WA_SPECIAL1;
488  else
489    {
490      PRINTF(2)("action %s could not be identified.\n", action);
491      return WA_NONE;
492    }
493}
494
495/**
496 * converts an action into a String
497 * @param action the action to convert
498 * @return a String matching the name of the action
499 */
500const char* Weapon::actionToChar(WeaponAction action)
501{
502  switch (action)
503  {
504    case WA_SHOOT:
505      return "shoot";
506      break;
507    case WA_CHARGE:
508      return "charge";
509      break;
510    case WA_RELOAD:
511      return "reload";
512      break;
513    case WA_ACTIVATE:
514      return "activate";
515      break;
516    case WA_DEACTIVATE:
517      return "deactivate";
518      break;
519    case WA_SPECIAL1:
520      return "special1";
521      break;
522    default:
523      return "none";
524      break;
525  }
526}
527
528/**
529 * Converts a String into a State.
530 * @param state the String input holding the State.
531 * @return The State if known, WS_NONE otherwise.
532 */
533WeaponState Weapon::charToState(const char* state)
534{
535  if (!strcmp(state, "none"))
536    return WS_NONE;
537  else if (!strcmp(state, "shooting"))
538    return WS_SHOOTING;
539  else if (!strcmp(state, "charging"))
540    return WS_CHARGING;
541  else if (!strcmp(state, "reloading"))
542    return WS_RELOADING;
543  else if (!strcmp(state, "activating"))
544    return WS_ACTIVATING;
545  else if (!strcmp(state, "deactivating"))
546    return WS_DEACTIVATING;
547  else if (!strcmp(state, "inactive"))
548    return WS_INACTIVE;
549  else if (!strcmp(state, "idle"))
550    return WS_IDLE;
551  else
552    {
553      PRINTF(2)("state %s could not be identified.\n", state);
554      return WS_NONE;
555    }
556}
557
558/**
559 * converts a State into a String
560 * @param state the state to convert
561 * @return a String matching the name of the state
562 */
563const char* Weapon::stateToChar(WeaponState state)
564{
565  switch (state)
566  {
567    case WS_SHOOTING:
568      return "shooting";
569      break;
570    case WS_CHARGING:
571      return "charging";
572      break;
573    case WS_RELOADING:
574      return "reloading";
575      break;
576    case WS_ACTIVATING:
577      return "activating";
578      break;
579    case WS_DEACTIVATING:
580      return "deactivating";
581      break;
582    case WS_IDLE:
583      return "idle";
584      break;
585    case WS_INACTIVE:
586      return "inactive";
587      break;
588    default:
589      return "none";
590      break;
591  }
592}
Note: See TracBrowser for help on using the repository browser.