Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/pawns/Pawn.cc @ 9270

Last change on this file since 9270 was 9257, checked in by landauf, 13 years ago

renamed RVName to radarname
cast to RadarViewable instead of SpaceShip to set the name (in PlayerInfo)

  • Property svn:eol-style set to native
File size: 15.1 KB
RevLine 
[2072]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
[8706]25 *      Simon Miescher
[2072]26 *
27 */
28
29#include "Pawn.h"
30
[3280]31#include <algorithm>
32
[3196]33#include "core/CoreIncludes.h"
[2896]34#include "core/GameMode.h"
[2072]35#include "core/XMLPort.h"
[3196]36#include "network/NetworkFunction.h"
37
[5735]38#include "infos/PlayerInfo.h"
[6417]39#include "controllers/Controller.h"
[5735]40#include "gametypes/Gametype.h"
[5737]41#include "graphics/ParticleSpawner.h"
[5735]42#include "worldentities/ExplosionChunk.h"
43#include "worldentities/BigExplosion.h"
44#include "weaponsystem/WeaponSystem.h"
45#include "weaponsystem/WeaponSlot.h"
46#include "weaponsystem/WeaponPack.h"
47#include "weaponsystem/WeaponSet.h"
[2072]48
49namespace orxonox
50{
51    CreateFactory(Pawn);
52
[7163]53    Pawn::Pawn(BaseObject* creator)
54        : ControllableEntity(creator)
55        , RadarViewable(creator, static_cast<WorldEntity*>(this))
[2072]56    {
57        RegisterObject(Pawn);
58
[2662]59        this->bAlive_ = true;
[3053]60        this->bReload_ = false;
[2072]61
62        this->health_ = 0;
63        this->maxHealth_ = 0;
64        this->initialHealth_ = 0;
[8706]65
[7163]66        this->shieldHealth_ = 0;
[8706]67        this->initialShieldHealth_ = 0;
68        this->maxShieldHealth_ = 100; //otherwise shield might increase to float_max
[7163]69        this->shieldAbsorption_ = 0.5;
[2072]70
[8706]71        this->reloadRate_ = 0;
72        this->reloadWaitTime_ = 1.0f;
73        this->reloadWaitCountdown_ = 0;
74
[2072]75        this->lastHitOriginator_ = 0;
76
[2662]77        this->spawnparticleduration_ = 3.0f;
[2098]78
[6417]79        this->aimPosition_ = Vector3::ZERO;
80
[2896]81        if (GameMode::isMaster())
[2662]82        {
83            this->weaponSystem_ = new WeaponSystem(this);
[3053]84            this->weaponSystem_->setPawn(this);
[2662]85        }
86        else
87            this->weaponSystem_ = 0;
88
89        this->setRadarObjectColour(ColourValue::Red);
90        this->setRadarObjectShape(RadarViewable::Dot);
91
[2072]92        this->registerVariables();
[3089]93
94        this->isHumanShip_ = this->hasLocalController();
[8891]95
[8329]96        this->setSyncMode(ObjectDirection::Bidirectional); // needed to synchronise e.g. aimposition
[2072]97    }
98
99    Pawn::~Pawn()
100    {
[2662]101        if (this->isInitialized())
102        {
103            if (this->weaponSystem_)
[5929]104                this->weaponSystem_->destroy();
[2662]105        }
[2072]106    }
107
108    void Pawn::XMLPort(Element& xmlelement, XMLPort::Mode mode)
109    {
110        SUPER(Pawn, XMLPort, xmlelement, mode);
111
[2662]112        XMLPortParam(Pawn, "health", setHealth, getHealth, xmlelement, mode).defaultValues(100);
[2072]113        XMLPortParam(Pawn, "maxhealth", setMaxHealth, getMaxHealth, xmlelement, mode).defaultValues(200);
114        XMLPortParam(Pawn, "initialhealth", setInitialHealth, getInitialHealth, xmlelement, mode).defaultValues(100);
[7163]115
116        XMLPortParam(Pawn, "shieldhealth", setShieldHealth, getShieldHealth, xmlelement, mode).defaultValues(0);
[8706]117        XMLPortParam(Pawn, "initialshieldhealth", setInitialShieldHealth, getInitialShieldHealth, xmlelement, mode).defaultValues(0);
118        XMLPortParam(Pawn, "maxshieldhealth", setMaxShieldHealth, getMaxShieldHealth, xmlelement, mode).defaultValues(100);
[7163]119        XMLPortParam(Pawn, "shieldabsorption", setShieldAbsorption, getShieldAbsorption, xmlelement, mode).defaultValues(0);
120
[2662]121        XMLPortParam(Pawn, "spawnparticlesource", setSpawnParticleSource, getSpawnParticleSource, xmlelement, mode);
122        XMLPortParam(Pawn, "spawnparticleduration", setSpawnParticleDuration, getSpawnParticleDuration, xmlelement, mode).defaultValues(3.0f);
123        XMLPortParam(Pawn, "explosionchunks", setExplosionChunks, getExplosionChunks, xmlelement, mode).defaultValues(7);
124
[3053]125        XMLPortObject(Pawn, WeaponSlot, "weaponslots", addWeaponSlot, getWeaponSlot, xmlelement, mode);
126        XMLPortObject(Pawn, WeaponSet, "weaponsets", addWeaponSet, getWeaponSet, xmlelement, mode);
[6417]127        XMLPortObject(Pawn, WeaponPack, "weapons", addWeaponPackXML, getWeaponPack, xmlelement, mode);
[8706]128
129        XMLPortParam(Pawn, "reloadrate", setReloadRate, getReloadRate, xmlelement, mode).defaultValues(0);
130        XMLPortParam(Pawn, "reloadwaittime", setReloadWaitTime, getReloadWaitTime, xmlelement, mode).defaultValues(1.0f);
[9254]131
[9257]132        XMLPortParam ( RadarViewable, "radarname", setRadarName, getRadarName, xmlelement, mode );
[2072]133    }
134
135    void Pawn::registerVariables()
136    {
[7163]137        registerVariable(this->bAlive_,           VariableDirection::ToClient);
138        registerVariable(this->health_,           VariableDirection::ToClient);
[8706]139        registerVariable(this->maxHealth_,        VariableDirection::ToClient);
[7163]140        registerVariable(this->shieldHealth_,     VariableDirection::ToClient);
[8706]141        registerVariable(this->maxShieldHealth_,  VariableDirection::ToClient);
[7163]142        registerVariable(this->shieldAbsorption_, VariableDirection::ToClient);
143        registerVariable(this->bReload_,          VariableDirection::ToServer);
144        registerVariable(this->aimPosition_,      VariableDirection::ToServer);  // For the moment this variable gets only transfered to the server
[2072]145    }
146
147    void Pawn::tick(float dt)
148    {
[2809]149        SUPER(Pawn, tick, dt);
[2072]150
[3053]151        this->bReload_ = false;
[2662]152
[8706]153        // TODO: use the existing timer functions instead
154        if(this->reloadWaitCountdown_ > 0)
155        {
156            this->decreaseReloadCountdownTime(dt);
157        }
158        else
159        {
160            this->addShieldHealth(this->getReloadRate() * dt);
161            this->resetReloadCountdown();
162        }
163
[3084]164        if (GameMode::isMaster())
[8706]165        {
[3087]166            if (this->health_ <= 0 && bAlive_)
[6864]167            {
[8706]168                this->fireEvent(); // Event to notify anyone who wants to know about the death.
[3087]169                this->death();
[6864]170            }
[8706]171        }
[2072]172    }
173
[7889]174    void Pawn::preDestroy()
175    {
176        // yay, multiple inheritance!
177        this->ControllableEntity::preDestroy();
178        this->PickupCarrier::preDestroy();
179    }
180
[2826]181    void Pawn::setPlayer(PlayerInfo* player)
182    {
183        ControllableEntity::setPlayer(player);
184
185        if (this->getGametype())
186            this->getGametype()->playerStartsControllingPawn(player, this);
187    }
188
189    void Pawn::removePlayer()
190    {
191        if (this->getGametype())
192            this->getGametype()->playerStopsControllingPawn(this->getPlayer(), this);
193
194        ControllableEntity::removePlayer();
195    }
196
[8706]197
[2072]198    void Pawn::setHealth(float health)
199    {
[8706]200        this->health_ = std::min(health, this->maxHealth_); //Health can't be set to a value bigger than maxHealth, otherwise it will be reduced at first hit
[2072]201    }
202
[8706]203    void Pawn::setShieldHealth(float shieldHealth)
[2072]204    {
[8706]205        this->shieldHealth_ = std::min(shieldHealth, this->maxShieldHealth_);
206    }
207
208    void Pawn::setMaxShieldHealth(float maxshieldhealth)
209    {
210        this->maxShieldHealth_ = maxshieldhealth;
211    }
212
213    void Pawn::setReloadRate(float reloadrate)
214    {
215        this->reloadRate_ = reloadrate;
216    }
217
218    void Pawn::setReloadWaitTime(float reloadwaittime)
219    {
220        this->reloadWaitTime_ = reloadwaittime;
221    }
222
223    void Pawn::decreaseReloadCountdownTime(float dt)
224    {
225        this->reloadWaitCountdown_ -= dt;
226    }
227
228    void Pawn::damage(float damage, float healthdamage, float shielddamage, Pawn* originator)
229    {
[2826]230        if (this->getGametype() && this->getGametype()->allowPawnDamage(this, originator))
231        {
[8706]232            if (shielddamage >= this->getShieldHealth())
[7163]233            {
234                this->setShieldHealth(0);
[8706]235                this->setHealth(this->health_ - (healthdamage + damage));
[7163]236            }
[8706]237            else
238            {
239                this->setShieldHealth(this->shieldHealth_ - shielddamage);
[7163]240
[8706]241                // remove remaining shieldAbsorpton-Part of damage from shield
242                shielddamage = damage * this->shieldAbsorption_;
243                shielddamage = std::min(this->getShieldHealth(),shielddamage);
244                this->setShieldHealth(this->shieldHealth_ - shielddamage);
[7163]245
[8706]246                // set remaining damage to health
247                this->setHealth(this->health_ - (damage - shielddamage) - healthdamage);
[7163]248            }
249
[2826]250            this->lastHitOriginator_ = originator;
251        }
[2072]252    }
253
[8706]254// TODO: Still valid?
255/* HIT-Funktionen
256    Die hit-Funktionen muessen auch in src/orxonox/controllers/Controller.h angepasst werden! (Visuelle Effekte)
257
258*/
259    void Pawn::hit(Pawn* originator, const Vector3& force, float damage, float healthdamage, float shielddamage)
[2072]260    {
[6417]261        if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) )
[2826]262        {
[8706]263            this->damage(damage, healthdamage, shielddamage, originator);
[2826]264            this->setVelocity(this->getVelocity() + force);
265        }
[2072]266    }
267
[8706]268
269    void Pawn::hit(Pawn* originator, btManifoldPoint& contactpoint, float damage, float healthdamage, float shielddamage)
[6417]270    {
271        if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) )
272        {
[8706]273            this->damage(damage, healthdamage, shielddamage, originator);
[6417]274
275            if ( this->getController() )
[8706]276                this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
[6417]277        }
278    }
279
[8706]280
[2072]281    void Pawn::kill()
282    {
283        this->damage(this->health_);
284        this->death();
285    }
286
[2662]287    void Pawn::spawneffect()
[2072]288    {
289        // play spawn effect
[6417]290        if (!this->spawnparticlesource_.empty())
[2662]291        {
292            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
293            effect->setPosition(this->getPosition());
294            effect->setOrientation(this->getOrientation());
295            effect->setDestroyAfterLife(true);
296            effect->setSource(this->spawnparticlesource_);
297            effect->setLifetime(this->spawnparticleduration_);
298        }
[2072]299    }
300
301    void Pawn::death()
302    {
[3033]303        this->setHealth(1);
[2826]304        if (this->getGametype() && this->getGametype()->allowPawnDeath(this, this->lastHitOriginator_))
305        {
306            // Set bAlive_ to false and wait for PawnManager to do the destruction
307            this->bAlive_ = false;
[2662]308
[2826]309            this->setDestroyWhenPlayerLeft(false);
[2662]310
[2826]311            if (this->getGametype())
312                this->getGametype()->pawnKilled(this, this->lastHitOriginator_);
[2662]313
[3038]314            if (this->getPlayer() && this->getPlayer()->getControllableEntity() == this)
315                this->getPlayer()->stopControl();
[2072]316
[2896]317            if (GameMode::isMaster())
[3087]318            {
319//                this->deathEffect();
320                this->goWithStyle();
321            }
[2826]322        }
[2662]323    }
[3087]324    void Pawn::goWithStyle()
325    {
326        this->bAlive_ = false;
327        this->setDestroyWhenPlayerLeft(false);
[2072]328
[3087]329        BigExplosion* chunk = new BigExplosion(this->getCreator());
330        chunk->setPosition(this->getPosition());
331
332    }
[2662]333    void Pawn::deatheffect()
334    {
[2072]335        // play death effect
[2662]336        {
337            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
338            effect->setPosition(this->getPosition());
339            effect->setOrientation(this->getOrientation());
340            effect->setDestroyAfterLife(true);
341            effect->setSource("Orxonox/explosion2b");
342            effect->setLifetime(4.0f);
343        }
344        {
345            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
346            effect->setPosition(this->getPosition());
347            effect->setOrientation(this->getOrientation());
348            effect->setDestroyAfterLife(true);
349            effect->setSource("Orxonox/smoke6");
350            effect->setLifetime(4.0f);
351        }
352        {
353            ParticleSpawner* effect = new ParticleSpawner(this->getCreator());
354            effect->setPosition(this->getPosition());
355            effect->setOrientation(this->getOrientation());
356            effect->setDestroyAfterLife(true);
357            effect->setSource("Orxonox/sparks");
358            effect->setLifetime(4.0f);
359        }
360        for (unsigned int i = 0; i < this->numexplosionchunks_; ++i)
361        {
362            ExplosionChunk* chunk = new ExplosionChunk(this->getCreator());
363            chunk->setPosition(this->getPosition());
364        }
[2072]365    }
366
[6417]367    void Pawn::fired(unsigned int firemode)
[2098]368    {
[6417]369        if (this->weaponSystem_)
370            this->weaponSystem_->fire(firemode);
[2098]371    }
372
[3053]373    void Pawn::reload()
374    {
375        this->bReload_ = true;
376    }
377
[2072]378    void Pawn::postSpawn()
379    {
380        this->setHealth(this->initialHealth_);
[2896]381        if (GameMode::isMaster())
[2662]382            this->spawneffect();
[2072]383    }
[2662]384
[2893]385    /* WeaponSystem:
386    *   functions load Slot, Set, Pack from XML and make sure all parent-pointers are set.
387    *   with setWeaponPack you can not just load a Pack from XML but if a Pack already exists anywhere, you can attach it.
388    *       --> e.g. Pickup-Items
389    */
[3053]390    void Pawn::addWeaponSlot(WeaponSlot * wSlot)
[2662]391    {
392        this->attach(wSlot);
393        if (this->weaponSystem_)
[3053]394            this->weaponSystem_->addWeaponSlot(wSlot);
[2662]395    }
396
397    WeaponSlot * Pawn::getWeaponSlot(unsigned int index) const
398    {
399        if (this->weaponSystem_)
[3053]400            return this->weaponSystem_->getWeaponSlot(index);
[2662]401        else
402            return 0;
403    }
404
[3053]405    void Pawn::addWeaponSet(WeaponSet * wSet)
[2662]406    {
407        if (this->weaponSystem_)
[3053]408            this->weaponSystem_->addWeaponSet(wSet);
[2662]409    }
410
[3053]411    WeaponSet * Pawn::getWeaponSet(unsigned int index) const
[2662]412    {
413        if (this->weaponSystem_)
[3053]414            return this->weaponSystem_->getWeaponSet(index);
[2662]415        else
416            return 0;
417    }
418
[3053]419    void Pawn::addWeaponPack(WeaponPack * wPack)
[2662]420    {
421        if (this->weaponSystem_)
[7163]422        {
[3053]423            this->weaponSystem_->addWeaponPack(wPack);
[7163]424            this->addedWeaponPack(wPack);
425        }
[2662]426    }
427
[6417]428    void Pawn::addWeaponPackXML(WeaponPack * wPack)
429    {
430        if (this->weaponSystem_)
[7163]431        {
[6417]432            if (!this->weaponSystem_->addWeaponPack(wPack))
433                wPack->destroy();
[7163]434            else
435                this->addedWeaponPack(wPack);
436        }
[6417]437    }
438
[3053]439    WeaponPack * Pawn::getWeaponPack(unsigned int index) const
[2662]440    {
441        if (this->weaponSystem_)
[3053]442            return this->weaponSystem_->getWeaponPack(index);
[2662]443        else
444            return 0;
445    }
446
[3089]447    //Tell the Map (RadarViewable), if this is a playership
448    void Pawn::startLocalHumanControl()
449    {
450//        SUPER(ControllableEntity, changedPlayer());
451        ControllableEntity::startLocalHumanControl();
452        this->isHumanShip_ = true;
453    }
[8891]454
455    void Pawn::changedVisibility(void)
456    {
457        SUPER(Pawn, changedVisibility);
[9254]458
459        // enable proper radarviewability when the visibility is changed
460        this->RadarViewable::settingsChanged();
[8891]461    }
462
[2072]463}
Note: See TracBrowser for help on using the repository browser.