Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/AsteroidMining_HS17/src/modules/asteroidmining/AsteroidMinable.cc @ 11641

Last change on this file since 11641 was 11641, checked in by remartin, 6 years ago

Changed detail in variable sized Array definition, should now build on Jenkins, too.

File size: 19.8 KB
RevLine 
[11547]1
[11550]2 /*   ORXONOX - the hottest 3D action shooter ever to exist
[11547]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:
25 *      Simon Miescher
26 *
27 */
28
29/*
[11550]30
[11547]31*
32*
33* An asteroid which can be destroyed. Some smaller asteroids are created and a pickup
34* spawns.
35*
36*
37*
38
39*/
40
[11551]41/*
42Veraenderungstagebuch
[11561]43++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[11547]44
[11618]45
[11615]46KNACKPUNKTE:
[11553]47
48OFFEN:
[11618]49
[11561]50o Add custom pickup 'resources'. Weird template stuff -> Problems setting 'size' and other properties? setNumber of Resources.
[11609]51--> PickupTemplateName_ in PickupSpawner ist ein string. Wird via getBaseClassIdentifier ausgelesen, daraus wird ein Pickupable fabriziert.
52--> MunitionPickup erbt von Pickup erbt von collectiblePickup erbt von Pickupable
53----> im MineralsPickup die isPickedUp()-Methode überschreiben?
54--> data_extern/images/effects: PNG's für die Pickups und GUI-Dinger.
[11640]55--> https://www.orxonox.net/jenkins/view/Management/job/orxonox_doxygen_trunk/javadoc/group___pickup.html
[11609]56
[11640]57o Anfangsgeschwindigkeit fuers Asteroidenfeld
58o Density doesn't add up to 1...
[11618]59o set collisionDamage? Just for static entities?
[11640]60o AsteroidBelt?
61
[11618]62o Dokumentieren mit @brief?
[11640]63o unregister -empty- asteroids from radar. (or turn them green or whatever)
64o Add sound effect (crunching etc. ) (No sound in space...)
[11561]65o Explosion parts
66o custom HUD
[11553]67
[11640]68
[11561]69HANDBUCH:
70o im Level-File includes/pickups.oxi importieren.
[11586]71o Bei der XML-Variante wird beim ersten Aufruf der Tick-Methode ein neuer Asteroid generiert,
72  damit die Groesse der Collision Shape korrekt initialisiert wird.
[11553]73
[11609]74FREMDANPASSUNGEN:
75Pickup-Zeug:
[11561]76o Pickup.h: Zugriffsänderung createSpawner
77o PickupSpawner.h: Zugriffsrechte setPickupTemplateName() und setMaxSpawnedItems()
[11609]78o PickupSpawner.h: In Tick() zwei Testbedingungen eingefuegt.
79o Pawn.h: Attribut acceptsPickups_ inklusive get/set.
[11553]80
[11640]81ERLEGTE FEHLER:
[11561]82o Rand() geht bis zu riesigen Nummern!
[11609]83o Pickupgenerierung: vgl. Fremdanpassungen.
84o Minimalbegrenzung fuer Masse vergessen.
[11561]85o Dynamische Definition -> putStuff-Methode, Werte noch nicht durchgesickert.
86o Error-Nachricht: Einfach Argumente leer lassen.
[11581]87o Pickups: setMaxSpawned funktioniert nicht -> Bastelloesung: Auf 2 statt eins setzen, erstes wird wohl direkt zerstoert.
[11587]88o setHealth: Wird mit Max verwurstelt, war 0.
89o Position nicht gesetzt -> alles im Ursprung, Kollision -> fliegt davon.
90o nimmt zuviel Schaden. -> wird mit maxHealth verwurstelt -> einfach auch setzen.
[11586]91
92o Groessenabhaengige Collison shape: Umweg ueber zweiten Konstruktor.
93o Absturz beim Asteroidengenerieren: Health war auf 0 gesetzt! Wurde nur bei der xml-Variante definiert.
[11609]94o Asteroiden fressen Pickups: Argument in Pawn, Test darauf in Tick() von PickupSpawner.
[11615]95o Man kann keine Arrays der Groesse 0 initialisieren, aber auch nicht per IF 2x definieren.
96o i++ einfach ganz verhindern, ++i stattdessen.
[11618]97o Discusting mixup with array length, accessing element a[len]...
98o unitialised mass value -> obese asteroid, physics bug.
[11586]99
[11615]100
[11587]101NOTIZEN:
102o SUPER entspricht ueberladen, andere Argumente der Methode.
[11609]103o Warnungsverhinderung anderswo: (void)pickedUp; // To avoid compiler warning.
[11587]104
[11609]105Was ist das?         friend class Pickupable;
106
107
108
[11551]109*/
110
111
[11547]112#include "../../orxonox/worldentities/pawns/Pawn.h"
113#include "../../orxonox/worldentities/WorldEntity.h"
114
115#include "AsteroidMinable.h"
116
117#include <algorithm>
118
119#include "core/CoreIncludes.h"
120#include "core/GameMode.h"
121#include "core/XMLPort.h"
122#include "core/EventIncludes.h"
[11615]123#include "network/NetworkFunction.h"
124#include "util/Math.h"
[11547]125
[11615]126
[11547]127// #include "infos/PlayerInfo.h"
128// #include "controllers/Controller.h"
129// #include "gametypes/Gametype.h"
130// #include "graphics/ParticleSpawner.h"
131// #include "worldentities/ExplosionChunk.h"
132// #include "worldentities/ExplosionPart.h"
133
134// #include "core/object/ObjectListIterator.h"
135// #include "controllers/FormationController.h"
136
137#include "../pickup/items/HealthPickup.h"
138#include "../pickup/PickupSpawner.h"
139#include "../pickup/Pickup.h"
[11553]140//#include "../pickup/pickup ..... pickupable
[11547]141#include "../objects/collisionshapes/SphereCollisionShape.h"
142#include "../../orxonox/graphics/Model.h"
143
144
145
146
147
148
[11615]149
[11547]150namespace orxonox
151{
152    RegisterClass(AsteroidMinable);
153
[11640]154    // @brief Standard constructor
[11586]155    AsteroidMinable::AsteroidMinable(Context* context) : Pawn(context){
[11581]156
[11586]157        RegisterObject(AsteroidMinable);
[11547]158
159        this->context = context;
[11551]160        this->initialised = false;
[11640]161        this->dropStuff = true; // Default
[11547]162
[11586]163        //Noetig, damit nicht sofort zerstoert?
164        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
[11547]165
[11586]166        // Old from Pawn
167        this->registerVariables();
[11553]168
[11618]169        //orxout() << "AsteroidMining:: Pseudo-Konstruktor passiert!" << endl;
[11547]170
[11586]171    }
[11547]172
[11640]173    // @brief Use this constructor with care. Mainly used internally, arguments are passed directly.
174    AsteroidMinable::AsteroidMinable(Context* c, float size, Vector3 position, Vector3 v, bool dropStuff) : Pawn(c){
[11547]175
[11586]176        RegisterObject(AsteroidMinable);
[11547]177
[11640]178        // The radar is able to detect whether an asteroid contains resources....
179        if(dropStuff){
180            this->setRadarObjectColour(ColourValue(1.0f, 1.0f, 0.0f, 1.0f));
181            this->setRadarObjectShape(RadarViewable::Shape::Dot);
182        }else{
183            // Somehow remove from radar?
184        }
185
[11586]186        this->setCollisionType(WorldEntity::CollisionType::Dynamic);
187        this->enableCollisionCallback();
[11581]188
[11586]189        // Default Values
[11587]190        this->context = c;
[11618]191        this->size = size;
192        this->health_ = 15*size; 
[11587]193        this->maxHealth_ = this->health_;
[11640]194        this->acceptsPickups_ = false; 
195        this->generateSmaller = true; 
196        this->dropStuff = dropStuff; 
[11609]197
[11587]198        this->setPosition(position);
[11640]199        this->setVelocity(v); // velocity = v; // The right one?
[11586]200        //this->roll = rand()*5; //etwas Drehung. richtige Variable
[11547]201
202
[11586]203        // Add Model    //<Model position="0,-40,40" yaw="90" pitch="-90" roll="0" scale="4" mesh="ast6.mesh" />
[11551]204        Model* hull = new Model(this->context);
205        // random one of the 6 shapes
206        char meshThingy[] = "";
[11618]207        sprintf(meshThingy, "ast%.0f.mesh", round(5*rnd())+1); //    sprintf(str, "Value of Pi = %f", M_PI);
[11551]208        hull->setMeshSource(meshThingy);
209        hull->setScale(this->size);
210        this->attach(hull);
[11547]211
[11551]212        // Collision shape
213        SphereCollisionShape* cs = new SphereCollisionShape(this->context);
[11553]214        cs->setRadius((this->size)*2); //OFFEN: Feinabstimmung der Radien. 2.5 in AsteroidField.lua
[11551]215        this->attachCollisionShape(cs); 
[11547]216
[11586]217        // Old from Pawn
218        this->registerVariables();
[11547]219
[11581]220        this->initialised=true; 
221
[11618]222        //orxout() << "AsteroidMining:: Initialisierung Zweitkonstruktor abgeschlosssssen." << endl;
[11581]223
[11547]224    }
225
[11586]226    AsteroidMinable::~AsteroidMinable(){
227
228    }
[11640]229    // @brief Helper method. Create a new asteroid to have an appropriate size for the collision shape etc.
[11586]230    void AsteroidMinable::putStuff(){
231
232        // Just create a new asteroid to avoid Collision shape scale problems etc.
[11640]233        AsteroidMinable* reborn = new AsteroidMinable(this->context, this->size, this->getPosition(), this->getVelocity(), this->dropStuff);
[11586]234        reborn->toggleShattering(true); // mainly here to avoid 'unused' warning.
[11640]235        this->bAlive_ = false;
236        this->destroyLater();
237        //this->~AsteroidMinable(); // seems dangerous, yields warning.  Necessary for efficiency?
[11586]238
239    }
240
[11547]241    void AsteroidMinable::XMLPort(Element& xmlelement, XMLPort::Mode mode)
242    {
243        SUPER(AsteroidMinable, XMLPort, xmlelement, mode);
244        //        XMLPortParam(PickupSpawner, "pickup", setPickupTemplateName, getPickupTemplateName, xmlelement, mode);
245        XMLPortParam(AsteroidMinable, "size", setSize, getSize, xmlelement, mode);
246
247    }
248
249    void AsteroidMinable::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
250    {
251        SUPER(AsteroidMinable, XMLEventPort, xmlelement, mode);
252
[11551]253        XMLPortEventState(AsteroidMinable, BaseObject, "vulnerability", setVulnerable, xmlelement, mode);
[11547]254    }
255
256    void AsteroidMinable::registerVariables()
257    {
[11551]258
259        registerVariable(this->size, VariableDirection::ToClient);
260        registerVariable(this->generateSmaller, VariableDirection::ToClient);
[11553]261
262        registerVariable(this->initialised, VariableDirection::ToClient);
263
264            //         float size;
265            // bool generateSmaller;
266            // bool initialised;
267
268            // Context* context;
[11547]269    }
270
271    void AsteroidMinable::tick(float dt)
272    {
[11618]273        if(!(this->initialised)){this->putStuff();} 
[11547]274
[11551]275        if(this->health_ <=0){this->death();}
276
[11547]277    }
278
279
280
[11586]281
[11547]282    void AsteroidMinable::death() //ueberschreiben
283    {
284
[11609]285        // orxout() << "AsteroidMinable::Death() aufgerufen." << endl;
[11547]286
[11581]287        // OFFEN: Sauber kapputten
288        // just copied other stuff:
289        // this->setHealth(1);
290        this->bAlive_ = false;
291        this->destroyLater();
292        this->setDestroyWhenPlayerLeft(false);
293        // pawn -> addExplosionPart
294        // this->goWithStyle();
[11551]295
[11547]296
[11640]297        // Pickups which can be harvested.
298        if(dropStuff){
299            PickupSpawner* thingy = new PickupSpawner(this->context);
300            // OFFEN: more precise size relation in custom resource pickup.
301            char tname[] = ""; // can-t overwrite strings easily in C (strcat etc.)
302            if(this->size <= 5){
303                strcat(tname, "smallmunitionpickup");
304            }else if(this->size <= 20){
305                strcat(tname, "mediummunitionpickup");
306            }else{
307                strcat(tname, "hugemunitionpickup");
308            }
309            thingy->setPickupTemplateName(tname);
310            thingy->setPosition(this->getPosition());
311            thingy->setMaxSpawnedItems(1); // Would be default anyways
312            thingy->setRespawnTime(0.2f);
[11609]313        }
[11581]314        // orxout() << "AsteroidMining::Death(): Passed Pickup stuff!" << endl;
[11553]315
[11561]316        // Smaller Parts = 'Children'
[11618]317        if(this->generateSmaller){this->spawnChildren();}
[11553]318
[11609]319        // orxout() << "Wieder retour in death() geschafft. " << endl;
[11553]320
[11547]321    }
322
323
[11615]324void AsteroidMinable::spawnChildren(){// Spawn smaller Children
325
[11551]326   
[11581]327    if (this->size <=1){return;} // Absicherung trivialer Fall
328
[11547]329    int massRem = this->size-1; //some mass is lost
[11615]330    int num = round(rnd()*(massRem-1)) + 1; // random number of children, at least one
[11609]331    if(num > 10){num = 10;} // no max function in C!
[11618]332    int masses[num]; // Masses of the asteroids, at least one.
[11640]333    //orxout() << "SpawnChildren(): Passed basic stuff. num = " << num << "; massRem(total) = "<< massRem << endl;
[11609]334
[11618]335    massRem = massRem-num; // mass is at least one, add again below.
[11609]336
[11615]337    // Randomnised spawning points for the new asteroids
[11641]338    float phi[num]; // assuming that it gets initialised to 0. Add (= {0.0})?
339    float theta[num];
[11640]340    float piG = 3.1415927410125732421875; //pi; // Math.pi ist statisch oder so.
[11609]341
[11618]342    float d_p = 2*piG/num;
343    float d_t = piG/num;
344    float p = d_p/2.0;
345    float t = d_t/2.0;
346    // float phiOffset = rnd()*2*pi; // Added everywhere to become independent of the coordinate system?
[11615]347    // float thetaOffset = rnd()*pi;
[11618]348    float rScaling; // scale radius to prevent asteroids from touching. (distance=AsteroidRadius/tan(sector/2))
349    if(num == 1 ){
350        rScaling = 1; // avoid tan(90). Unused.
351    }else{
[11609]352
[11618]353        rScaling = tan(t); 
[11609]354
[11618]355        int pos; // insert at random position (linear probing) in array, to get some randomness. 
356        for(int it = 0; it<num; ++it){
[11609]357
[11618]358            pos = mod((int)(rnd()*num),num); 
359            while(phi[pos] != 0.0){// find empty spot in array
360                pos = (int)mod(++pos, num);
361            }
362            phi[pos] = p + it*d_p;// set angle there
[11561]363
[11618]364            pos = mod((int)(rnd()*num),num);
365            while(theta[pos] != 0.0){
366                pos = (int)mod(++pos, num);
367            }
368            theta[pos] = t + it*d_t;
[11615]369        }
370    }
[11561]371
[11618]372    //orxout() << "SpawnChildren(): Phi: "; printArrayString(phi);
373    //orxout() << "SpawnChildren(): Theta: "; printArrayString(theta);
[11640]374    //orxout() << "SpawnChildren(): Passed angle stuff. " << endl;
[11561]375
[11640]376    // 'Triangular', discrete probability "density" with max at the expected value massRem/num at a. a+b = c
[11615]377    if(massRem>0){ // Required to avoid array of size 0 or access problems
378        int c = massRem;
[11641]379        float probDensity[c];
[11581]380
[11615]381        int a = round(massRem/num);
382        int b = c-a;
[11618]383       
[11615]384        int z = 0;
[11618]385        float dProbA = 1.0/(a*a + 3.0*a + 2.0); // one 'probability unit' for discrete ramp function. Gauss stuff.
386        for(z = 0; z<=a; ++z){probDensity[z] = (z+1)*dProbA; } // rising part
387
388        float dProbB = 1.0/(b*b +3.0*b + 2.0);
389        for(z = 0; z<b; ++z){probDensity[c-z] = (z+1)*dProbB;} // falling part
[11615]390   
[11640]391        // // Just for testing:
392        // float sum = 0.0;
393        // for(int globi = 0; globi<c; ++globi){
394        //     orxout() << "pDensity at [" << globi << "] is: " << probDensity[globi] << endl;
395        //     sum = sum+ probDensity[globi];
396        // }
397        // orxout() << "Sum of densities should b 1, it is: " << sum << endl;
[11581]398
[11618]399        // Distributing the mass to individual asteroids
400        int result;
401        float rVal;// between 0 and 1
402        float probSum;
403        for(int trav = 0; trav<num; ++trav){
404            result = 0;// reset
405            rVal = rnd();// between 0 and 1
[11640]406            // orxout() << "Random Value picked: " << rVal << endl;
[11618]407            probSum = probDensity[0]; 
408            //orxout() << "Sum at start: " << probSum << endl;
409
410            while(rVal>probSum && result<massRem){// Not yet found && there-s smth to distribute (Incrementing once inside!)
[11640]411                if(result<(massRem-2)){probSum = probSum + probDensity[result+1];} // avoid logical/acess error
[11615]412                ++result;
[11640]413                // orxout() << "Sum so far: " << probSum << ". Just added " << probDensity[result+1] <<  endl;
[11615]414            }
[11561]415
[11615]416            massRem = massRem-result;
[11618]417            masses[trav] = 1 +result; // at least one
[11640]418            // orxout() << "Mass chosen for child " << trav << " is: " << masses[trav] << endl;
[11615]419
[11547]420        }
[11618]421    }else{// Everyone has mass 1. Initialising the array to 1 doesn-t seem to work. Hideous C language!
422        for(int schnaegg = 0; schnaegg<num; ++schnaegg){
423            masses[schnaegg] = 1;
424        }
[11615]425    }
[11551]426
[11640]427    // orxout() << "SpawnChildren(): Masses: "; printArrayString(masses);
428    // orxout() << "SpawnChildren(): Passed mass stuff. " << endl;
[11551]429
[11618]430    // Creating the 'chlidren':
431    for(int fisch = 0; fisch<num; ++fisch){
[11551]432
[11618]433        Vector3* pos = new Vector3(0,0,0); // Position offset
434        if(num > 1){// not required if there-s just one child
435            float r = masses[fisch]/rScaling;
436            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
437        }
438       
[11640]439        // orxout() << "Creating asteroid with mass " << masses[fisch] << " at relative postition " << *pos << endl;
440        AsteroidMinable* child = new AsteroidMinable(this->context, masses[fisch], this->getPosition() + *pos, this->getVelocity(), this->dropStuff);
[11551]441
[11581]442        if(child == nullptr){
443            orxout(internal_error, context::pickups) << "Weird, can't create new AsteroidMinable." << endl;
444        }
[11553]445
[11547]446    }
[11640]447    // orxout() << "Leaving spawnChildren() method. " << endl;
[11547]448}
449
450
[11581]451    void AsteroidMinable::hit(Pawn* originator, const Vector3& force, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
[11547]452
[11581]453        orxout() << "AsteroidMining::Hit(Variante 1) Dings aufgerufen. " << endl;
[11547]454
[11640]455        // Kollision mit anderem Asteroid oder Pickup verhindern. In diesem Fall einfach nichts tun.
[11581]456        // Wird staending aufgerufen -> Rechenleistung?
457        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
458        this->damage(damage, healthdamage, shielddamage, originator, cs);
459        this->setVelocity(this->getVelocity() + force);
460
461
462
463        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
464        // {
465        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
466        //     this->setVelocity(this->getVelocity() + force);
467        // }
468    }
469
470    void AsteroidMinable::hit(Pawn* originator, btManifoldPoint& contactpoint, const btCollisionShape* cs, float damage, float healthdamage, float shielddamage){
471
[11609]472        //orxout() << "AsteroidMining::Hit(Variante 2) Dings aufgerufen. " << endl;
[11581]473        // Kollision mit anderem Asteroid oder Pickup (OFFEN: evtl. Spawner oder irgendwas?) verhindern. In diesem Fall einfach nichts tun.
474        // Wird staending aufgerufen -> Rechenleistung?
475        if(orxonox_cast<AsteroidMinable*>(originator) || orxonox_cast<Pickup*>(originator)){return;}
476
[11609]477        //orxout() << "Schaden. HP: " << this->health_ << " Dmg: " << damage << " hDmg: " << healthdamage << " sDmg: " << shielddamage << endl;
[11581]478
479        this->damage(damage, healthdamage, shielddamage, originator, cs);
480
481
482
483
484        // if (this->getGametype() && this->getGametype()->allowPawnHit(this, originator))// && (!this->getController() || !this->getController()->getGodMode()) )
485        // {
486        //     this->damage(damage, healthdamage, shielddamage, originator, cs);
487
488        //     //if ( this->getController() )
489        //     //    this->getController()->hit(originator, contactpoint, damage); // changed to damage, why shielddamage?
490        // }
491    }
492
[11640]493    // @brief Just for testing. Don-t work anyways.
[11618]494    void AsteroidMinable::printArrayString(float thingy[]){ // Don-t work!
[11581]495
[11618]496        orxout() << "[" ; //<< endl; 
497        char frag[] = "";
498        int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
499        for(int m = 0; m< (len-2); ++m){
500            sprintf(frag, "%.5f, ", thingy[m]);
501            orxout() << frag << endl;//std::flush;
502        }
503        sprintf(frag, "%.5f]", thingy[len-1]);
504        orxout() << frag << endl; // Just print it here! No ugly passing.
505    }
[11581]506
[11640]507    // @brief Just for testing. Don-t work anyways.
[11618]508    void AsteroidMinable::printArrayString(int thingy[]){
[11581]509
[11618]510        orxout() << "[" ; //<< endl;
511        char frag[] = "";
512        int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
513        for(int m = 0; m< (len-2); ++m){
514            sprintf(frag, "%.0i, ", thingy[m]);
515            orxout() << frag << endl;//std::flush;
516            printf("TEst");
517        }
[11581]518
[11618]519        sprintf(frag, "%.0i]", thingy[len-1]); // last element
520        orxout() << frag << endl; // Just print it here! No ugly passing.
521    }
[11581]522
[11618]523    // void AsteroidMinable::printArrayString(int thingy[]){
524    //     char res[] = "[";
525    //     //strcat(res, "[");
526    //     char frag[] = "";
527
528    //     int len = (int)(sizeof(thingy)/sizeof(thingy[0]));
529    //     for(int m = 0; m< (len-1); ++m){
530    //         sprintf(frag, "%.0i, ", thingy[m]);
531    //         strcat(res, frag);
532    //     }
533    //     sprintf(frag, "%.0i]", thingy[len]);
534    //     strcat(res, frag); // last element
535
536    //     orxout() << res << endl; // Just print it here! No ugly passing.
537
538    //     // static char result[(sizeof(res)/sizeof("")] = res; // define as static, would get deleted otherwise.
539    //     // char *result = malloc(sizeof(res)/sizeof("") + 1);
540    //     // *result = res;
541    //     // return result;
542    // }
543
[11640]544}
Note: See TracBrowser for help on using the repository browser.