/* ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Fabian 'x3n' Landau * Co-authors: * Simon Miescher * */ /* * * * An asteroid which can be destroyed. Some smaller asteroids are created and a pickup * spawns. * * * */ /* Veraenderungstagebuch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ KNACKPUNKTE: o Collision Shape-Problem (Funktioniert nur, wenn im Konstruktor) -> Mit Factory-Methode oder so basteln. o Maximale Hitpunkte = 200? o Neue Asteroiden generieren -> Absturz --> Kollidiert sofort mit irgendetwas, death() wird mehrfach aufgerufen. --> Funktioniert der Test in den hit()-Methoden? --> Welcher Aufruf loest die death()-Methode auf? OFFEN: o Add custom pickup 'resources'. Weird template stuff -> Problems setting 'size' and other properties? setNumber of Resources. o Explosion parts o custom HUD HANDBUCH: o im Level-File includes/pickups.oxi importieren. Anpassungen Pickup-Zeug: o Pickup.h: Zugriffsänderung createSpawner o PickupSpawner.h: Zugriffsrechte setPickupTemplateName() und setMaxSpawnedItems() ERLEGT: o Rand() geht bis zu riesigen Nummern! o Pickupgenerierung: vgl. Anpassungen. o Dummes fisch-- statt fisch++ , Endlosschleife! o Dynamische Definition -> putStuff-Methode, Werte noch nicht durchgesickert. o Error-Nachricht: Einfach Argumente leer lassen. o Pickups: setMaxSpawned funktioniert nicht -> Bastelloesung: Auf 2 statt eins setzen, erstes wird wohl direkt zerstoert. */ #include "../../orxonox/worldentities/pawns/Pawn.h" #include "../../orxonox/worldentities/WorldEntity.h" #include "AsteroidMinable.h" #include #include "core/CoreIncludes.h" #include "core/GameMode.h" #include "core/XMLPort.h" #include "core/EventIncludes.h" #include "network/NetworkFunction.h" // #include "infos/PlayerInfo.h" // #include "controllers/Controller.h" // #include "gametypes/Gametype.h" // #include "graphics/ParticleSpawner.h" // #include "worldentities/ExplosionChunk.h" // #include "worldentities/ExplosionPart.h" // #include "core/object/ObjectListIterator.h" // #include "controllers/FormationController.h" #include "../pickup/items/HealthPickup.h" #include "../pickup/PickupSpawner.h" #include "../pickup/Pickup.h" //#include "../pickup/pickup ..... pickupable #include "../objects/collisionshapes/SphereCollisionShape.h" #include "../../orxonox/graphics/Model.h" namespace orxonox { RegisterClass(AsteroidMinable); AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context) { RegisterObject(AsteroidMinable); // Old stuff from pawn this->setRadarObjectColour(ColourValue(1.0f, 1.0f, 0.0f, 1.0f)); this->setRadarObjectShape(RadarViewable::Shape::Dot); this->setCollisionType(WorldEntity::CollisionType::Dynamic); this->bAlive_ = true; this->bVulnerable_ = true; this->enableCollisionCallback(); // Default Values this->generateSmaller = true; //this->setHealth(50); this->size = 10; // customSize this->context = context; this->initialised = false; //this->roll = rand()*5; //etwas Drehung. richtige Variable //this = new AsteroidMinable() // DELETE if other stuff works! (wrong size etc.) SphereCollisionShape* cs = new SphereCollisionShape(this->context); cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien this->attachCollisionShape(cs); // Old from Pawn this->registerVariables(); orxout() << "AsteroidMining:: Konstruktor passiert!" << endl; } AsteroidMinable::~AsteroidMinable() { } void AsteroidMinable::putStuff(){ // Add Model // Model* hull = new Model(this->context); // random one of the 6 shapes char meshThingy[] = ""; sprintf(meshThingy, "ast%.0f.mesh", (round((5*(double)rand()/(double)RAND_MAX))+1)); // sprintf(str, "Value of Pi = %f", M_PI); hull->setMeshSource(meshThingy); hull->setScale(this->size); this->attach(hull); // Collision shape SphereCollisionShape* cs = new SphereCollisionShape(this->context); cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien. 2.5 in AsteroidField.lua this->attachCollisionShape(cs); this->initialised=true; orxout() << "AsteroidMining:: Initialisierung abgeschlosssssen." << endl; } void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(AsteroidMinable, XMLPort, xmlelement, mode); // XMLPortParam(PickupSpawner, "pickup", setPickupTemplateName, getPickupTemplateName, xmlelement, mode); XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode); } void AsteroidMinable::XMLEventPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(AsteroidMinable, XMLEventPort, xmlelement, mode); XMLPortEventState(AsteroidMinable, BaseObject, "vulnerability", setVulnerable, xmlelement, mode); } void AsteroidMinable::registerVariables() { registerVariable(this->bAlive_, VariableDirection::ToClient); registerVariable(this->bVulnerable_, VariableDirection::ToClient); registerVariable(this->health_, VariableDirection::ToClient); registerVariable(this->maxHealth_, VariableDirection::ToClient); registerVariable(this->size, VariableDirection::ToClient); registerVariable(this->generateSmaller, VariableDirection::ToClient); registerVariable(this->initialised, VariableDirection::ToClient); //registerVariable(this->context, VariableDirection::ToClient); // can't link that since it's a context // float size; // bool generateSmaller; // bool initialised; // Context* context; } void AsteroidMinable::tick(float dt) { // SUPER(Pawn, tick, dt); if(!(this->initialised)){this->putStuff();} if(this->health_ <=0){this->death();} } void AsteroidMinable::setSize(float s){ this->size = s; this->health_ = 5*s;// capped at 200 in pawn or smth? this->setHealth(health_); } float AsteroidMinable::getSize(){ return this->size; } void AsteroidMinable::death() //ueberschreiben { orxout() << "AsteroidMinable::Death() aufgerufen." << endl; // OFFEN: Sauber kapputten // just copied other stuff: // this->setHealth(1); this->bAlive_ = false; this->destroyLater(); this->setDestroyWhenPlayerLeft(false); // pawn -> addExplosionPart // this->goWithStyle(); // // Stuff that can be harvested. // PickupSpawner* thingy = new PickupSpawner(this->context); // // OFFEN: more precise size relation in custom resource pickup. // char tname[] = ""; // can-t overwrite strings easily in C (strcat etc.) // if(this->size <= 5){ // strcat(tname, "smallmunitionpickup"); // }else if(this->size <= 20){ // strcat(tname, "mediummunitionpickup"); // }else{ // strcat(tname, "hugemunitionpickup"); // } // thingy->setPickupTemplateName(tname); // thingy->setPosition(this->getPosition()); // thingy->setMaxSpawnedItems(2); // The first somehow gets destroyed immediately. // thingy->setRespawnTime(0.5f); // orxout() << "AsteroidMining::Death(): Passed Pickup stuff!" << endl; // Smaller Parts = 'Children' if(this->generateSmaller){ this->spawnChildren(); } orxout() << "Wieder retour in death() geschafft. " << endl; // if (this->getGametype() && this->getGametype()->allowPawnDeath(this, this->lastHitOriginator_)) // { // // Set bAlive_ to false and wait for destroyLater() to do the destruction // this->bAlive_ = false; // this->destroyLater(); // this->setDestroyWhenPlayerLeft(false); // } } void AsteroidMinable::spawnChildren(){ if (this->size <=1){return;} // Absicherung trivialer Fall // Spawn smaller Children int massRem = this->size-1; //some mass is lost int num = round((massRem-1)*(double)rand() / (double)RAND_MAX)+1; // random number of children, at least one // Tweak towards bigger junks? num = 1; // zum Testen mal nur einen generieren. massRem = massRem-num; int extra = 0; //orxout() << "Number of Children: " << num << endl; for(int fisch=num; fisch>=1; --fisch){ // to distribute remaining mass //orxout() << "AsteroidMining::spawnChildren(): Fisch-Variable: " << fisch << endl; if(fisch==1){ extra = massRem; }else{ extra = round(massRem*(double)rand() / (double)RAND_MAX); massRem = massRem-extra; } //orxout() << "Mass chosen: " << extra+1 << endl; //orxout() << "AsteroidMining::spawnChildren(): Inside for-loop." << endl; //Spawn this child Game crashes! AsteroidMinable* child = new AsteroidMinable(this->context); // if(!(child == nullptr)){//Errorgebastel // Position zu spaet gesetzt? Tick nicht atomar -> falsche Groesse evtl? if(child == nullptr){ orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl; } child->setSize(extra + 1); //OFFEN:Kollision der Kinder verhindern //Relativ zu Elternteil automatisch? //Typ position:rand()*Vektoriwas? //pawn->getWorldPosition() + Vector3(30,0,-30); child->setPosition(this->getPosition() + Vector3(num*5, 0, 0)); //child->setPosition(Vector3(0,0,0)); //orxout() << "Done: Creating new Asteroid" << endl; // } // Pawn* pawn = this->carrierToPawnHelper(); // if(pawn == nullptr) // If the PickupCarrier is no Pawn, then this pickup is useless and therefore is destroyed. // this->Pickupable::destroy(); // //Attach to pawn // Drone* drone = new Drone(pawn->getContext()); // this is neccessary because the projectiles fired need a valid creator for the particlespawner (when colliding against something) // drone->addTemplate(this->getDroneTemplate()); } orxout() << "Leaving spawnChildren() method. " << endl; } void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){ orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl; // Kollision mit anderem Asteroid oder Pickup (OFFEN: evtl. Spawner oder irgendwas?) verhindern. In diesem Fall einfach nichts tun. // Wird staending aufgerufen -> Rechenleistung? if(orxonox_cast(originator) || orxonox_cast(originator)){return;} this->damage(damage, healthdamage, shielddamage, originator, cs); this->setVelocity(this->getVelocity() + force); // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) ) // { // this->damage(damage, healthdamage, shielddamage, originator, cs); // this->setVelocity(this->getVelocity() + force); // } } void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){ orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl; // Kollision mit anderem Asteroid oder Pickup (OFFEN: evtl. Spawner oder irgendwas?) verhindern. In diesem Fall einfach nichts tun. // Wird staending aufgerufen -> Rechenleistung? if(orxonox_cast(originator) || orxonox_cast(originator)){return;} this->damage(damage, healthdamage, shielddamage, originator, cs); // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) ) // { // this->damage(damage, healthdamage, shielddamage, originator, cs); // //if ( this->getController() ) // // this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage? // } } // Cast-Test aus movableEntity(): // Pawn* victim = orxonox_cast(otherObject); // if (victim) //Pawn: // void Pawn::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage) // { // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) ) // { // this->damage(damage, healthdamage, shielddamage, originator, cs); // this->setVelocity(this->getVelocity() + force); // } // } // void Pawn::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage) // { // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator) && (!this->getController() || !this->getController()->getGodMode()) ) // { // this->damage(damage, healthdamage, shielddamage, originator, cs); // if ( this->getController() ) // this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage? // } // } // /** // @brief // Virtual function that gets called when this object collides with another. // @param otherObject // The object this one has collided into. // @param ownCollisionShape // The collision shape of the other object // @param contactPoint // Contact point provided by Bullet. Holds more information and can me modified. See return value. // @return // Returning false means that no modification to the contactPoint has been made. Return true otherwise! // @note // Condition is that enableCollisionCallback() was called. // */ // virtual inline bool collidesAgainst(WorldEntity* otherObject, const btCollisionShape* ownCollisionShape, btManifoldPoint& contactPoint) // { return false; } /* With false, Bullet assumes no modification to the collision objects. */ // //! Enables the collidesAgainst(.) function. The object doesn't respond to collision otherwise! // inline void enableCollisionCallback() // { this->bCollisionCallbackActive_ = true; this->collisionCallbackActivityChanged(); } // //! Disables the collidesAgainst(.) function. @see enableCollisionCallback() // inline void disableCollisionCallback() // { this->bCollisionCallbackActive_ = false; this->collisionCallbackActivityChanged(); } // //! Tells whether there could be a collision callback via collidesAgainst(.) // inline bool isCollisionCallbackActive() const // { return this->bCollisionCallbackActive_; } // //! Enables or disables collision response (default is of course on) // inline void setCollisionResponse(bool value) // { this->bCollisionResponseActive_ = value; this->collisionResponseActivityChanged(); } // //! Tells whether there could be a collision response // inline bool hasCollisionResponse() // { return this->bCollisionResponseActive_; } } /* void DronePickup::changedUsed(void) { SUPER(DronePickup, changedUsed); // If the pickup has transited to used. if(this->isUsed()) { Pawn* pawn = this->carrierToPawnHelper(); if(pawn == nullptr) // If the PickupCarrier is no Pawn, then this pickup is useless and therefore is destroyed. this->Pickupable::destroy(); //Attach to pawn Drone* drone = new Drone(pawn->getContext()); // this is neccessary because the projectiles fired need a valid creator for the particlespawner (when colliding against something) drone->addTemplate(this->getDroneTemplate()); Controller* controller = drone->getController(); DroneController* droneController = orxonox_cast(controller); if(droneController != nullptr) { droneController->setOwner(pawn); } Vector3 spawnPosition = pawn->getWorldPosition() + Vector3(30,0,-30); drone->setPosition(spawnPosition); // The pickup has been used up. this->setUsed(false); } else { // If either the pickup can only be used once or it is continuous and used up, it is destroyed upon setting it to unused. if(this->isOnce() || (this->isContinuous() )) { this->Pickupable::destroy(); } } } */