Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/towerdefenseFS15/src/modules/towerdefense/TowerDefense.cc @ 10430

Last change on this file since 10430 was 10430, checked in by erbj, 9 years ago

added functionality: Waves with different combinations of spaceships, eggs and ufos ; added different tower templates and progressing pricing for the towers; also 5 tower to upgrade instead of 3

  • Property svn:eol-style set to native
File size: 21.0 KB
Line 
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 *
24 *   Co-authors:
25 *      ...
26 *
27 *NACHRICHT:
28 *
29 * Hier empfehle ich euch die gesamte Spielogik unter zu bringen. Viele Funktionen werden automatisch
30 * bei gewissen Ereignissen aufgerufen bzw. lösen Ereignisse aus
31 *
32 *Z.B:
33 * start() //wird aufgerufen, bevor das Spiel losgeht
34 * end() //wenn man diese Funktion aufruft wird
35 * pawnKilled() // wird aufgerufen, wenn ein Pawn stirbt (z.B: wenn )
36 * playerScored() // kann man aufrufen um dem Spieler Punkte zu vergeben.
37 *
38 *
39 *TIPP: Eclipse hilft euch schnell auf bereits vorhanden Funktionen zuzugreifen:
40 * einfach "this->" eingeben und kurz warten. Dann tauch eine Liste mit Vorschlägen auf. Wenn ihr jetzt weiter
41 * tippt, werden die Vorschläge entsprechend gefiltert.
42 *
43 *
44 *TIPP: schaut euch mal Tetris::createStone() an. Dort wird ein TetrisStone-Objekt (ControllableEntity) erzeugt,
45 * ihm ein Template zugewiesen (welches vorher im Level definiert wurde und dem CenterPoint übergeben wurde)
46 * Ähnlich könnt ihr vorgehen, um einen Turm zu erzeugen. (Zusätzlich braucht ein Turm noch einen Controller)
47 * z.B: WaypointPatrolController. Wenn kein Team zugewiesen wurde bekämpft ein WaypointPatrolController alles,
48 * was in seiner Reichweite liegt.
49 *
50 *
51 *HUD:
52 * Ein Gametype kann ein HUD (Head up Display haben.) Z.B: hat Pong eine Anzeige welcher Spieler wieviele Punkte hat.
53 * Generell kann man a) Grafiken oder b) Zeichen in einer HUD anzeigen.
54 * Fuer den ersten Schritt reicht reiner Text.
55 *
56 * a)
57 * PongScore.cc uebernehmen und eigene Klasse draus machen.
58 * Wenn ihr bloss anzeigen wollt wieviele Punkte der Spieler bereits erspielt hat (Punkte = Kapital fuer neue Tuerme) dann orientiert ihr euch an
59 * TetrisScore.cc (im pCuts branch): http://www.orxonox.net/browser/code/branches/pCuts/src/modules/tetris/TetrisScore.cc
60 * Ich habe TetrisScore lediglich dazu gebraucht, um eine Variable auf dem HUD auszugeben. Ein Objekt fuer statischen Text gibt es bereits.
61 *
62 * b)
63 * Im naesten Schritt erstellt man die Vorlage fuer das HUD-Objekt: siehe /data/overlays/pongHUD
64 * OverlayText ist eine Vorlage fuer statischen text zb: "Points Scored:". Aus mir nicht erklaerlichen Gruenden sollte man die OverlayText
65 * Objekte immer erst nach dem PongScore anlegen.
66 *
67 * c)  Im TowerDefense gamtype muss im Constructor noch das HUD-Template gesetzt werden.
68 *
69 * d) in CMakeLists.txt noch das Module includen das fuer die Overlays zustaendig ist. Siehe das gleiche File im Pong module.
70 *
71 *
72 *
73 */
74#include "TowerDefense.h"
75#include "TowerDefenseTower.h"
76#include "TowerDefenseCenterpoint.h"
77//#include "TDCoordinate.h"
78#include "worldentities/SpawnPoint.h"
79#include "worldentities/pawns/Pawn.h"
80#include "worldentities/pawns/SpaceShip.h"
81#include "controllers/WaypointController.h"
82#include "graphics/Model.h"
83#include "infos/PlayerInfo.h"
84#include "chat/ChatManager.h"
85#include "core/CoreIncludes.h"
86/* Part of a temporary hack to allow the player to add towers */
87#include "core/command/ConsoleCommand.h"
88#include <cmath>
89
90
91namespace orxonox
92{
93    static const std::string __CC_addTower_name  = "addTower";
94    static const std::string __CC_upgradeTower_name = "upgradeTower";
95    static const int upgradeCost = 20;
96    static const int towerCost = 20;
97
98
99    SetConsoleCommand("TowerDefense", __CC_addTower_name,  &TowerDefense::addTower ).addShortcut().defaultValues(1);
100    SetConsoleCommand("TowerDefense", __CC_upgradeTower_name, &TowerDefense::upgradeTower).addShortcut().defaultValues(0);
101
102    RegisterUnloadableClass(TowerDefense);
103
104    TowerDefense::TowerDefense(Context* context) : TeamDeathmatch(context)
105    {
106        RegisterObject(TowerDefense);
107/*
108        for (int i=0; i < 16 ; i++){
109            for (int j = 0; j< 16 ; j++){
110                towermatrix[i][j] = NULL;
111            }
112        }*/
113
114        //Timer for the waves (10 seconds between the waves)
115        selecter = NULL;
116        this->player_ = NULL;       
117        this->setHUDTemplate("TowerDefenseHUD");
118        this->nextwaveTimer_.setTimer(10, false, createExecutor(createFunctor(&TowerDefense::nextwave, this)));
119        this->nextwaveTimer_.stopTimer();
120        this->waves_ = 0;
121        this->time = 0;
122        this->credit_ = 0;
123        this->lifes_ = 0;
124        this->timeSetTower_ = 0;
125        spaceships =15;
126        eggs=3;
127        ufos=7;
128        randomships=5;
129
130
131        ModifyConsoleCommand(__CC_addTower_name).setObject(this);
132        ModifyConsoleCommand(__CC_upgradeTower_name).setObject(this);
133    }
134
135    TowerDefense::~TowerDefense()
136    {
137        /* Part of a temporary hack to allow the player to add towers */
138        if (this->isInitialized())
139        {
140            ModifyConsoleCommand(__CC_addTower_name).setObject(NULL);
141            ModifyConsoleCommand(__CC_upgradeTower_name).setObject(NULL);
142        }
143    }
144
145    void TowerDefense::setCenterpoint(TowerDefenseCenterpoint *centerpoint)
146    {
147        orxout() << "Centerpoint now setting..." << endl;
148        this->center_ = centerpoint;
149        orxout() << "Centerpoint now set..." << endl;
150    }
151
152    void TowerDefense::start()
153    {
154        if (center_ != NULL) // There needs to be a TowerDefenseCenterpoint, i.e. the area the game takes place.
155        {
156            if (selecter == NULL)
157            {
158                selecter = new TowerDefenseSelecter(this->center_->getContext());               
159            }
160            selecter->addTemplate(center_->getSelecterTemplate());
161            center_->attach(selecter);
162        }
163        else // If no centerpoint was specified, an error is thrown and the level is exited.
164        {
165            orxout(internal_error) << "Jump: No Centerpoint specified." << endl;
166            return;
167        }
168
169        TeamDeathmatch::start();
170
171        // Waypoints: [1,3] [10,3] [10,11] [13,11] -> add the points to a matrix so the player cant place towers on the path
172        for (int i=0; i < 16 ; i++)
173        {
174            for (int j = 0; j< 16 ; j++)
175            {
176                towerModelMatrix[i][j] = NULL;
177                towerTurretMatrix[i][j] = NULL;
178            }
179        }
180
181       
182
183        if (player_ != NULL)
184        {
185            //this->player_->startControl(selecter);
186        }
187        else
188        {
189            orxout() << "player=NULL" << endl;
190        }
191
192
193        Model* dummyModel = new Model(this->center_->getContext());
194
195        //the path of the spacehips has to be blocked, so that no towers can be build there
196        for (int k=0; k<3; k++)
197            towerModelMatrix[1][k]=dummyModel;
198        for (int l=1; l<11; l++)
199                towerModelMatrix[l][3]=dummyModel;
200        for (int m=3; m<12; m++)
201                towerModelMatrix[10][m]=dummyModel;
202        for (int n=10; n<14; n++)
203                towerModelMatrix[n][11]=dummyModel;
204        for (int o=13; o<16; o++)
205                towerModelMatrix[13][o]=dummyModel;
206
207
208        //set initial credits, lifes and WaveNumber
209        this->setCredit(100);
210        this->setLifes(100);
211        this->setWaveNumber(0);
212        time=0.0;
213
214        /*
215        //adds initial towers
216        for (int i=0; i <7; i++){
217            addTower(i+3,4);
218        }
219                */
220    }
221
222    // Generates a TowerDefenseEnemy. Uses Template "enemytowerdefense". Sets position at first waypoint of path.
223    void TowerDefense::addTowerDefenseEnemy(std::vector<TDCoordinate*> path, int templatenr){
224
225
226        TowerDefenseEnemy* en1 = new TowerDefenseEnemy(this->center_->getContext());
227       
228        switch(templatenr)
229        {
230        case 1 :
231            en1->addTemplate("enemytowerdefense1");
232            en1->setScale(3);
233            en1->lookAt(Vector3(0,0,100000));
234            en1->setHealth(en1->getHealth() +50 + this->getWaveNumber()*4);
235            break;
236
237        case 2 :
238            en1->addTemplate("enemytowerdefense2");
239            en1->setScale(2);
240            en1->lookAt(Vector3(0,0,100000));
241            en1->roll(Degree(120));
242            en1->setHealth(en1->getHealth() -30 + this->getWaveNumber()*4);
243            //  en1->setShieldHealth(en1->getShield() = this->getWaveNumber()*2))
244            break;
245
246        case 3 :
247            en1->addTemplate("enemytowerdefense3");
248            en1->setScale(1);
249            en1->lookAt(Vector3(0,0,100000));
250            en1->roll(Degree(120));
251            en1->setHealth(en1->getHealth() -10 + this->getWaveNumber()*4);
252            break;
253        }
254
255        en1->setTeam(2);
256        en1->getController();
257        en1->setPosition(path.at(0)->get3dcoordinate());       
258        TowerDefenseEnemyvector.push_back(en1);
259
260        for(unsigned int i = 0; i < path.size(); ++i)
261        {
262            en1->addWaypoint((path.at(i)));
263        }
264    }
265
266
267    void TowerDefense::end()
268    {
269
270        TeamDeathmatch::end();
271        ChatManager::message("Match is over! Gameover!");
272
273    }
274
275    void TowerDefense::spawnPlayer(PlayerInfo* player)
276    {
277        assert(player);
278        this->player_ = player;
279
280        if (selecter->getPlayer() == NULL)
281        {
282            this->player_ = player;
283            player->startControl(selecter);
284            players_[player].state_ = PlayerState::Alive;
285        } 
286    }
287
288    /**
289    @brief
290        Get the player.
291    @return
292        Returns a pointer to the player. If there is no player, NULL is returned.
293    */
294    PlayerInfo* TowerDefense::getPlayer(void) const
295    {
296        return this->player_;
297    }
298
299    //not working yet
300    void TowerDefense::upgradeTower(int x,int y)
301    {
302        TDCoordinate* coord = new TDCoordinate(x,y);
303        x = coord->GetX();
304        y = coord->GetY();
305       
306
307        if (!this->hasEnoughCreditForTower(upgradeCost))
308        {
309            orxout() << "not enough credit: " << (this->getCredit()) << " available, " << upgradeCost << " needed.";
310            return;
311        }
312
313
314        Model* dummyModel2 = new Model(this->center_->getContext());
315
316        if (towerModelMatrix [x][y] == NULL || (towerModelMatrix [x][y])->getMeshSource() == dummyModel2->getMeshSource())
317        {
318            orxout() << "no tower on this position" << endl;
319            return;
320        }
321
322        else
323        {
324            (towerTurretMatrix [x][y])->upgradeTower();
325            switch(towerTurretMatrix[x][y]->upgrade)
326                   {
327                   case 1 :
328                           towerModelMatrix[x][y]->setMeshSource("TD_T2.mesh");
329                           break;
330
331                   case 2 :
332                           towerModelMatrix[x][y]->setMeshSource("TD_T3.mesh");
333                           break;
334                   case 3 :
335                           towerModelMatrix[x][y]->setMeshSource("TD_T4.mesh");
336                           break;
337                   case 4 :
338                           towerModelMatrix[x][y]->setMeshSource("TD_T5.mesh");
339                           break;
340
341                   }
342
343            this->buyTower(upgradeCost);
344        }
345    }
346
347    /*adds Tower at Position (x,y) and reduces credit and adds the point to the towermatrix. template ("towerturret")
348    so towers have ability if the turrets
349    */
350
351    void TowerDefense::addTower(int x, int y)
352    {       
353        TDCoordinate* coord = new TDCoordinate(x,y);
354        x = coord->GetX();
355        y = coord->GetY();
356
357
358        if (!this->hasEnoughCreditForTower(towerCost))
359        {
360            orxout() << "not enough credit: " << (this->getCredit()) << " available, " << towerCost << " needed.";
361            return;
362        }
363
364        if (towerModelMatrix [x][y]!=NULL)
365        {
366            orxout() << "not possible to put tower here!!" << endl;
367            return;
368        }
369
370/*
371        unsigned int width = this->center_->getWidth();
372        unsigned int height = this->center_->getHeight();
373*/
374
375        int tileScale = (int) this->center_->getTileScale();
376
377        /*if (x > 15 || y > 15 || x < 0 || y < 0)
378        {
379            //Hard coded: TODO: let this depend on the centerpoint's height, width and fieldsize (fieldsize doesn't exist yet)
380            orxout() << "Can not add Tower: x and y should be between 0 and 15" << endl;
381            return;
382        }*/
383
384        //orxout() << "Will add tower at (" << (x-8) * tileScale << "," << (y-8) * tileScale << ")" << endl;
385        orxout() << "Will add tower at (" << x << "," << y << ")" << endl;
386
387
388        //Create Model
389        Model* newTowerModel = new Model(this->center_->getContext());
390        newTowerModel->setMeshSource("TD_T1.mesh");
391        newTowerModel->setScale(30);
392        newTowerModel->pitch(Degree(90));
393        newTowerModel->setPosition(static_cast<float>((x-8) * tileScale), static_cast<float>((y-8) * tileScale), 80);
394
395        //Creates tower
396        TowerDefenseTower* towernew = new TowerDefenseTower(this->center_->getContext());
397        towernew->setPosition(static_cast<float>((x-8) * tileScale), static_cast<float>((y-8) * tileScale), 275);
398        towernew->setGame(this);
399        towernew->setTeam(1);
400
401        //Reduce credit
402         this->buyTower(towerCost);
403         towerModelMatrix [x][y]= newTowerModel;
404         towerTurretMatrix [x][y]= towernew;
405    }   
406
407    bool TowerDefense::hasEnoughCreditForTower(int towerCost)
408    {
409        return ((this->getCredit()) >= towerCost);
410    }
411
412
413    bool TowerDefense::hasEnoughCreditForUpgrade()
414    {
415        return true;
416    }
417
418 
419    void TowerDefense::nextwave()
420    {
421        TowerDefenseEnemyvector.clear();
422        waves_++;
423        time=0;
424        float randomnumber1 = rand()*100*5;
425        float randomnumber2 = rand()*100*1;
426        float randomnumber3 = rand()*100*1.5;
427
428        float totalnumber = (randomnumber1 + randomnumber2 + randomnumber3)*1.3;
429
430        int newspaceships = (int)(maxspaceships* randomnumber1 / totalnumber);
431        int neweggs = (int)(maxspaceships*randomnumber2 / totalnumber);
432        int newufos = (int)(maxspaceships*randomnumber3 / totalnumber);
433        int newrandomships = maxspaceships -spaceships - eggs - ufos;
434        int spaceships =newspaceships;
435        int eggs=neweggs;
436        int ufos=newufos;
437        int randomships=newrandomships;
438
439    }
440
441    void TowerDefense::tick(float dt)
442    {
443        SUPER(TowerDefense, tick, dt);
444        time +=dt;
445        timeSetTower_ +=dt;
446
447        //Check if tower has to be set (because TowerDefenseSelecter asks for it)
448        if(timeSetTower_ >= 0.25)
449        {
450                timeSetTower_ =0;
451                        if(selecter != NULL && selecter->firePressed_)
452                        {
453
454                                int x = selecter->selectedPos_->GetX();
455                                int y = selecter->selectedPos_->GetY();
456                                Model* dummyModel2 = new Model(this->center_->getContext());
457
458
459
460                                if(towerModelMatrix[x][y] == NULL)
461                                {
462                                        addTower(x,y);
463                                }
464                                else
465                                {
466                                        if(!((towerModelMatrix [x][y])->getMeshSource() == dummyModel2->getMeshSource()))
467                                        {
468                                                towerTurretMatrix[x][y]->upgradeTower();
469                                        if(towerTurretMatrix[x][y]->upgrade < towerTurretMatrix[x][y]->upgradeMax)
470                                        {
471                                                this->buyTower((int)(upgradeCost*(std::pow(1.5,towerTurretMatrix[x][y]->upgrade))));
472                                                        switch(towerTurretMatrix[x][y]->upgrade)
473                                                   {
474                                                           case 1 :
475                                                                   towerModelMatrix[x][y]->setMeshSource("TD_T2.mesh");
476                                                                   break;
477
478                                                           case 2 :
479                                                                   towerModelMatrix[x][y]->setMeshSource("TD_T3.mesh");
480                                                                   break;
481                                           case 3 :
482                                                   towerModelMatrix[x][y]->setMeshSource("TD_T4.mesh");
483                                                   break;
484                                           case 4 :
485                                                   towerModelMatrix[x][y]->setMeshSource("TD_T5.mesh");
486                                                   break;
487
488                                                   }
489
490
491                                        }
492                                        }
493                                }
494                                selecter->firePressed_ = false;
495                        }
496        }
497
498        TDCoordinate* coord1 = new TDCoordinate(1,1);
499        std::vector<TDCoordinate*> path;
500        path.push_back(coord1);
501
502
503        int enemytype = this->getWaveNumber() % 3 +1;
504
505
506        if(time>=TowerDefenseEnemyvector.size() && TowerDefenseEnemyvector.size() < maxspaceships)
507                {
508                        orxout() << "enemyerstellen" << endl;
509                //adds different types of enemys depending on the WaveNumber progressively making the combination of enemys more difficult
510                if(spaceships>0)
511                {
512                        addTowerDefenseEnemy(path, 1);
513                        spaceships--;
514
515                }else if(ufos>0)
516                {
517                        addTowerDefenseEnemy(path, 3);
518                        ufos--;
519                }else if(eggs>0)
520                {
521                        addTowerDefenseEnemy(path, 2);
522                        eggs--;
523                }else if(randomships>0)
524                {
525                        addTowerDefenseEnemy(path, rand() % 3 +1);
526                        randomships--;
527
528                }
529
530                }
531
532
533        Vector3* endpoint = new Vector3(500, 700, 150);
534        //if ships are at the end they get destroyed
535        for(unsigned int i =0; i < TowerDefenseEnemyvector.size(); ++i)
536        {
537            if(TowerDefenseEnemyvector.at(i) != NULL && TowerDefenseEnemyvector.at(i)->isAlive())
538            {
539                //destroys enemys at the end of the path and reduces the life by 1. no credits gifted
540
541                Vector3 ship = TowerDefenseEnemyvector.at(i)->getRVWorldPosition();
542                float distance = ship.distance(*endpoint);
543
544                if(distance <50){
545                    TowerDefenseEnemyvector.at(i)->destroy();
546                    this->reduceLifes(1);
547                    this->buyTower(1);
548                    if (this->getLifes()==0)
549                    {
550                        this->end();
551                    }
552                }
553            }
554        }
555
556        //goes thorugh vector to see if an enemy is still alive. if not next wave is launched
557        int count= 0;
558        for(unsigned int i =0; i < TowerDefenseEnemyvector.size(); ++i)
559        {
560            if(TowerDefenseEnemyvector.at(i)!= NULL)
561            {
562                ++count;
563            }
564        }
565
566        if (count == 0 && !this->nextwaveTimer_.isActive())
567            this->nextwaveTimer_.startTimer();
568
569/*            time2 +=dt;
570        if(count== 0)
571        {
572            if(time2 > 10)
573            {
574                TowerDefenseEnemyvector.clear();
575                this->nextwave();
576                time=0;
577                time2=0;
578            }
579        }
580*/
581
582    }
583
584
585    // Function to test if we can add waypoints using code only. Doesn't work yet
586
587    // THE PROBLEM: WaypointController's getControllableEntity() returns null, so it won't track. How do we get the controlableEntity to NOT BE NULL???
588    /*
589    void TowerDefense::addWaypointsAndFirstEnemy()
590    {
591        SpaceShip *newShip = new SpaceShip(this->center_);
592        newShip->addTemplate("spaceshipassff");
593
594        WaypointController *newController = new WaypointController(newShip);
595        newController->setAccuracy(3);
596
597        Model *wayPoint1 = new Model(newController);
598        wayPoint1->setMeshSource("crate.mesh");
599        wayPoint1->setPosition(7,-7,5);
600        wayPoint1->setScale(0.2);
601
602        Model *wayPoint2 = new Model(newController);
603        wayPoint2->setMeshSource("crate.mesh");
604        wayPoint2->setPosition(7,7,5);
605        wayPoint2->setScale(0.2);
606
607        newController->addWaypoint(wayPoint1);
608        newController->addWaypoint(wayPoint2);
609
610        // The following line causes the game to crash
611
612        newShip->setController(newController);
613//        newController -> getPlayer() -> startControl(newShip);
614        newShip->setPosition(-7,-7,5);
615        newShip->setScale(0.1);
616        //newShip->addSpeed(1);
617
618
619
620//      this->center_->attach(newShip);
621    }
622    */
623    /*
624    void TowerDefense::playerEntered(PlayerInfo* player)
625    {
626        TeamDeathmatch::playerEntered(player);
627
628        const std::string& message = player->getName() + " entered the game";
629        ChatManager::message(message);
630    }
631
632    bool TowerDefense::playerLeft(PlayerInfo* player)
633    {
634        bool valid_player = TeamDeathmatch::playerLeft(player);
635
636        if (valid_player)
637        {
638            const std::string& message = player->getName() + " left the game";
639            ChatManager::message(message);
640        }
641
642        return valid_player;
643    }
644
645
646    void TowerDefense::pawnKilled(Pawn* victim, Pawn* killer)
647    {
648        if (victim && victim->getPlayer())
649        {
650            std::string message;
651            if (killer)
652            {
653                if (killer->getPlayer())
654                    message = victim->getPlayer()->getName() + " was killed by " + killer->getPlayer()->getName();
655                else
656                    message = victim->getPlayer()->getName() + " was killed";
657            }
658            else
659                message = victim->getPlayer()->getName() + " died";
660
661            ChatManager::message(message);
662        }
663
664        TeamDeathmatch::pawnKilled(victim, killer);
665    }
666
667    void TowerDefense::playerScored(PlayerInfo* player, int score)
668    {
669        Gametype::playerScored(player, score);
670    }*/
671}
Note: See TracBrowser for help on using the repository browser.