/* 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: OFFEN: o Add custom pickup 'resources'. Weird template stuff -> Problems setting 'size' and other properties? setNumber of Resources. --> PickupTemplateName_ in PickupSpawner ist ein string. Wird via getBaseClassIdentifier ausgelesen, daraus wird ein Pickupable fabriziert. --> MunitionPickup erbt von Pickup erbt von collectiblePickup erbt von Pickupable ----> im MineralsPickup die isPickedUp()-Methode überschreiben? --> data_extern/images/effects: PNG's für die Pickups und GUI-Dinger. --> https://www.orxonox.net/jenkins/view/Management/job/orxonox_doxygen_trunk/javadoc/group___pickup.html o Anfangsgeschwindigkeit fuers Asteroidenfeld o Density doesn't add up to 1... o set collisionDamage? Just for static entities? o AsteroidBelt? o Dokumentieren mit @brief? o unregister -empty- asteroids from radar. (or turn them green or whatever) o Add sound effect (crunching etc. ) (No sound in space...) o Explosion parts o custom HUD HANDBUCH: o im Level-File includes/pickups.oxi importieren. o Bei der XML-Variante wird beim ersten Aufruf der Tick-Methode ein neuer Asteroid generiert, damit die Groesse der Collision Shape korrekt initialisiert wird. FREMDANPASSUNGEN: Pickup-Zeug: o Pickup.h: Zugriffsänderung createSpawner o PickupSpawner.h: Zugriffsrechte setPickupTemplateName() und setMaxSpawnedItems() o PickupSpawner.h: In Tick() zwei Testbedingungen eingefuegt. o Pawn.h: Attribut acceptsPickups_ inklusive get/set. ERLEGTE FEHLER: o Rand() geht bis zu riesigen Nummern! o Pickupgenerierung: vgl. Fremdanpassungen. o Minimalbegrenzung fuer Masse vergessen. 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. o setHealth: Wird mit Max verwurstelt, war 0. o Position nicht gesetzt -> alles im Ursprung, Kollision -> fliegt davon. o nimmt zuviel Schaden. -> wird mit maxHealth verwurstelt -> einfach auch setzen. o Groessenabhaengige Collison shape: Umweg ueber zweiten Konstruktor. o Absturz beim Asteroidengenerieren: Health war auf 0 gesetzt! Wurde nur bei der xml-Variante definiert. o Asteroiden fressen Pickups: Argument in Pawn, Test darauf in Tick() von PickupSpawner. o Man kann keine Arrays der Groesse 0 initialisieren, aber auch nicht per IF 2x definieren. o i++ einfach ganz verhindern, ++i stattdessen. o Discusting mixup with array length, accessing element a[len]... o unitialised mass value -> obese asteroid, physics bug. NOTIZEN: o SUPER entspricht ueberladen, andere Argumente der Methode. o Warnungsverhinderung anderswo: (void)pickedUp; // To avoid compiler warning. Was ist das? friend class Pickupable; */ #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 "util/Math.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); // @brief Standard constructor AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context){ RegisterObject(AsteroidMinable); this->context = context; this->initialised = false; this->dropStuff = true; // Default //Noetig, damit nicht sofort zerstoert? this->setCollisionType(WorldEntity::CollisionType::Dynamic); // Old from Pawn this->registerVariables(); //orxout() << "AsteroidMining:: Pseudo-Konstruktor passiert!" << endl; } // @brief Use this constructor with care. Mainly used internally, arguments are passed directly. AsteroidMinable::AsteroidMinable(Context* c, float size, Vector3 position, Vector3 v, bool dropStuff) : Pawn(c){ RegisterObject(AsteroidMinable); // The radar is able to detect whether an asteroid contains resources.... if(dropStuff){ this->setRadarObjectColour(ColourValue(1.0f, 1.0f, 0.0f, 1.0f)); this->setRadarObjectShape(RadarViewable::Shape::Dot); }else{ // Somehow remove from radar? } this->setCollisionType(WorldEntity::CollisionType::Dynamic); this->enableCollisionCallback(); // Default Values this->context = c; this->size = size; this->health_ = 15*size; this->maxHealth_ = this->health_; this->acceptsPickups_ = false; this->generateSmaller = true; this->dropStuff = dropStuff; this->setPosition(position); this->setVelocity(v); // velocity = v; // The right one? //this->roll = rand()*5; //etwas Drehung. richtige Variable // Add Model // Model* hull = new Model(this->context); // random one of the 6 shapes char meshThingy[] = ""; sprintf(meshThingy, "ast%.0f.mesh", round(5*rnd())+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); // Old from Pawn this->registerVariables(); this->initialised=true; //orxout() << "AsteroidMining:: Initialisierung Zweitkonstruktor abgeschlosssssen." << endl; } AsteroidMinable::~AsteroidMinable(){ } // @brief Helper method. Create a new asteroid to have an appropriate size for the collision shape etc. void AsteroidMinable::putStuff(){ // Just create a new asteroid to avoid Collision shape scale problems etc. AsteroidMinable* reborn = new AsteroidMinable(this->context, this->size, this->getPosition(), this->getVelocity(), this->dropStuff); reborn->toggleShattering(true); // mainly here to avoid 'unused' warning. this->bAlive_ = false; this->destroyLater(); //this->~AsteroidMinable(); // seems dangerous, yields warning. Necessary for efficiency? } 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->size, VariableDirection::ToClient); registerVariable(this->generateSmaller, VariableDirection::ToClient); registerVariable(this->initialised, VariableDirection::ToClient); // float size; // bool generateSmaller; // bool initialised; // Context* context; } void AsteroidMinable::tick(float dt) { if(!(this->initialised)){this->putStuff();} if(this->health_ <=0){this->death();} } 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(); // Pickups which can be harvested. if(dropStuff){ 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(1); // Would be default anyways thingy->setRespawnTime(0.2f); } // orxout() << "AsteroidMining::Death(): Passed Pickup stuff!" << endl; // Smaller Parts = 'Children' if(this->generateSmaller){this->spawnChildren();} // orxout() << "Wieder retour in death() geschafft. " << endl; } void AsteroidMinable::spawnChildren(){// Spawn smaller Children if (this->size <=1){return;} // Absicherung trivialer Fall int massRem = this->size-1; //some mass is lost int num = round(rnd()*(massRem-1)) + 1; // random number of children, at least one if(num > 10){num = 10;} // no max function in C! int masses[num]; // Masses of the asteroids, at least one. //orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl; massRem = massRem-num; // mass is at least one, add again below. // Randomnised spawning points for the new asteroids float phi[num]; // assuming that it gets initialised to 0. Add (= {0.0})? float theta[num]; float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so. float d_p = 2*piG/num; float d_t = piG/num; float p = d_p/2.0; float t = d_t/2.0; // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system? // float thetaOffset = rnd()*pi; float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2)) if(num == 1 ){ rScaling = 1; // avoid tan(90). Unused. }else{ rScaling = tan(t); int pos; // insert at random position (linear probing) in array, to get some randomness. for(int it = 0; it0){ // Required to avoid array of size 0 or access problems int c = massRem; float probDensity[c]; int a = round(massRem/num); int b = c-a; int z = 0; float dProbA = 1.0/(a*a + 3.0*a + 2.0); // one 'probability unit' for discrete ramp function. Gauss stuff. for(z = 0; z<=a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part float dProbB = 1.0/(b*b +3.0*b + 2.0); for(z = 0; zprobSum && result 1){// not required if there-s just one child float r = masses[fisch]/rScaling; pos = new Vector3(r*sin(theta[fisch])*cos(phi[fisch]), r*sin(theta[fisch])*sin(phi[fisch]), r*cos(theta[fisch])); // convert spheric coordinates to vector } // orxout() << "Creating asteroid with mass " << masses[fisch] << " at relative postition " << *pos << endl; AsteroidMinable* child = new AsteroidMinable(this->context, masses[fisch], this->getPosition() + *pos, this->getVelocity(), this->dropStuff); if(child == nullptr){ orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl; } } // 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 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;} //orxout() << "Schaden. HP: " << this->health_ << " Dmg: " << damage << " hDmg: " << healthdamage << " sDmg: " << shielddamage << endl; 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? // } } // @brief Just for testing. Don-t work anyways. void AsteroidMinable::printArrayString(float thingy[]){ // Don-t work! orxout() << "[" ; //<< endl; char frag[] = ""; int len = (int)(sizeof(thingy)/sizeof(thingy[0])); for(int m = 0; m< (len-2); ++m){ sprintf(frag, "%.5f, ", thingy[m]); orxout() << frag << endl;//std::flush; } sprintf(frag, "%.5f]", thingy[len-1]); orxout() << frag << endl; // Just print it here! No ugly passing. } // @brief Just for testing. Don-t work anyways. void AsteroidMinable::printArrayString(int thingy[]){ orxout() << "[" ; //<< endl; char frag[] = ""; int len = (int)(sizeof(thingy)/sizeof(thingy[0])); for(int m = 0; m< (len-2); ++m){ sprintf(frag, "%.0i, ", thingy[m]); orxout() << frag << endl;//std::flush; printf("TEst"); } sprintf(frag, "%.0i]", thingy[len-1]); // last element orxout() << frag << endl; // Just print it here! No ugly passing. } // void AsteroidMinable::printArrayString(int thingy[]){ // char res[] = "["; // //strcat(res, "["); // char frag[] = ""; // int len = (int)(sizeof(thingy)/sizeof(thingy[0])); // for(int m = 0; m< (len-1); ++m){ // sprintf(frag, "%.0i, ", thingy[m]); // strcat(res, frag); // } // sprintf(frag, "%.0i]", thingy[len]); // strcat(res, frag); // last element // orxout() << res << endl; // Just print it here! No ugly passing. // // static char result[(sizeof(res)/sizeof("")] = res; // define as static, would get deleted otherwise. // // char *result = malloc(sizeof(res)/sizeof("") + 1); // // *result = res; // // return result; // } }