Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: new Definitions in the WeaponManager-class

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