Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/modules/towerdefense/TowerDefense.cc @ 10918

Last change on this file since 10918 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

  • Property svn:eol-style set to native
File size: 13.2 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 "worldentities/SpawnPoint.h"
78#include "controllers/WaypointController.h"
79#include "graphics/Model.h"
80#include "infos/PlayerInfo.h"
81#include "chat/ChatManager.h"
82#include "core/CoreIncludes.h"
83
84namespace orxonox
85{
86    RegisterUnloadableClass(TowerDefense);
87
88    TowerDefense::TowerDefense(Context* context) : TeamDeathmatch(context)
89    {
90        RegisterObject(TowerDefense);
91
92        selecter = nullptr;
93        this->player_ = nullptr;
94        this->setHUDTemplate("TowerDefenseHUD");
95        this->waveNumber_ = 0;
96        this->timeSinceLastSpawn_ = 0.0;
97        this->timeUntilNextWave_ = 0.0;
98        this->credit_ = 0;
99        this->lifes_ = 0;
100        this->waveSize_ = 0;
101        offset_ = Vector3(0,0,10);
102    }
103
104    TowerDefense::~TowerDefense()
105    {
106        if (this->isInitialized())
107        {
108
109        }
110    }
111
112    void TowerDefense::setCenterpoint(TowerDefenseCenterpoint *centerpoint)
113    {
114        this->center_ = centerpoint;
115    }
116
117    void TowerDefense::start()
118    {       
119        if (center_ != nullptr) // There needs to be a TowerDefenseCenterpoint, i.e. the area the game takes place.
120        {
121            if (selecter == nullptr)
122            {
123                selecter = new TowerDefenseSelecter(this->center_->getContext());               
124            }
125            selecter->addTemplate(center_->getSelecterTemplate());
126            center_->attach(selecter);
127        }
128        else // If no centerpoint was specified, an error is thrown and the level is exited.
129        {
130            orxout(internal_error) << "Jump: No Centerpoint specified." << endl;
131            return;
132        }
133
134        enemies_.clear();
135
136        createFields();
137        TeamDeathmatch::start();
138
139        //set initial credits, lifes and WaveNumber
140        this->setCredit(1000);
141        this->setLifes(100);       
142        this->timeSinceLastSpawn_ = 0.0;
143        this->timeUntilNextWave_ = 5.0;
144        this->waveSize_ = 0;
145        this->setWaveNumber(0);
146    }
147
148    // Generates a TowerDefenseEnemy. Uses Template "enemytowerdefense". Sets position at first waypoint of path.
149    void TowerDefense::addTowerDefenseEnemy(int templatenr)
150    {
151        TowerDefenseEnemy* en1 = new TowerDefenseEnemy(this->center_->getContext());
152       
153        switch(templatenr)
154        {
155        case 1 :
156            en1->addTemplate("enemytowerdefense1");
157            en1->setScale(3);
158            en1->setHealth(en1->getHealth() + this->getWaveNumber()*4);
159            break;
160
161        case 2 :
162            en1->addTemplate("enemytowerdefense2");
163            en1->setScale(2);
164            en1->setHealth(en1->getHealth() + this->getWaveNumber()*4);
165            break;
166
167        case 3 :
168            en1->addTemplate("enemytowerdefense3");
169            en1->setScale(1);
170            en1->setHealth(en1->getHealth() + this->getWaveNumber()*4);
171            break;
172        }       
173
174        en1->setTeam(2);
175
176        WaypointController* controller = (WaypointController*)(en1->getXMLController());
177
178        if (controller != nullptr && waypoints_.size() > 1)
179        {
180            en1->setPosition(waypoints_.at(0)->getPosition() + offset_);
181            en1->setOrientation(Vector3(0,0,10), Degree(0));
182            en1->setDirection(Vector3(0,1,0));
183            en1->lookAt(waypoints_.at(1)->getPosition() + offset_);
184
185            for (TowerDefenseField* field : waypoints_)
186            {
187                orxonox::WeakPtr<MovableEntity> waypoint = new MovableEntity(this->center_->getContext());
188                waypoint->setPosition(field->getPosition() + offset_);
189                controller->addWaypoint(waypoint);
190            }
191        }
192
193        enemies_.push_back(en1);
194    }
195
196
197    void TowerDefense::end()
198    {
199
200        TeamDeathmatch::end();
201        ChatManager::message("Match is over! Gameover!");
202
203    }
204
205    void TowerDefense::spawnPlayer(PlayerInfo* player)
206    {
207        assert(player);
208        player_ = player;
209
210        if (selecter->getPlayer() == nullptr)
211        {
212            player_->startControl(selecter);
213            players_[player].state_ = PlayerState::Alive;
214        } 
215    }
216
217    /**
218    @brief
219        Get the player.
220    @return
221        Returns a pointer to the player. If there is no player, nullptr is returned.
222    */
223    PlayerInfo* TowerDefense::getPlayer(void) const
224    {
225        return this->player_;
226    }
227
228    //not working yet
229    void TowerDefense::addTower(int x,int y)
230    {
231        TDCoordinate* coord = new TDCoordinate(x,y);
232        x = coord->GetX();
233        y = coord->GetY();
234
235        int cost = center_->getTowerCost(1);
236
237        if (fields_[x][y]->isFree() == true && getCredit() >= cost)
238        {
239            payCredit(cost);
240            fields_[x][y]->createTower(1);
241        }
242    }
243
244    /*adds Tower at Position (x,y) and reduces credit and adds the point to the towermatrix. template ("towerturret")
245    so towers have ability if the turrets
246    */
247
248    void TowerDefense::upgradeTower(int x, int y)
249    {   
250        TDCoordinate* coord = new TDCoordinate(x,y);
251        x = coord->GetX();
252        y = coord->GetY();     
253
254        int cost = center_->getTowerCost(fields_[x][y]->getUpgrade() + 1);
255
256        if (fields_[x][y]->isFree() == false && fields_[x][y]->canUpgrade() == true && getCredit() >= cost)
257        {
258            payCredit(cost);
259            fields_[x][y]->upgrade();
260        }
261    }   
262
263    void TowerDefense::tick(float dt)
264    {
265        SUPER(TowerDefense, tick, dt);
266
267        if (hasStarted() == false || player_ == nullptr)
268        {
269            return;
270        }
271        timeUntilNextWave_ -= dt;
272        timeSinceLastSpawn_ += dt;
273
274        //build/upgrade tower at selecter position
275        if (selecter != nullptr && selecter->buildTower_ == true)
276        {
277            selecter->buildTower_ = false;
278
279            if (getField(selecter->selectedPos_)->canUpgrade() == true)
280            {
281                upgradeTower(selecter->selectedPos_->GetX(), selecter->selectedPos_->GetY());
282            }
283            else
284            {
285                addTower(selecter->selectedPos_->GetX(), selecter->selectedPos_->GetY());
286            }           
287        }
288       
289        for (std::list<WeakPtr<TowerDefenseEnemy>>::iterator it = enemies_.begin(); it != enemies_.end(); )
290        {
291            if (*it == nullptr)
292            {
293                // the enemy was destroyed by a tower - remove it from the list
294                enemies_.erase(it++);
295                addCredit(1);
296            }
297            else
298            {
299                //if ships are at the end they get destroyed
300                Vector3 ship = (*it)->getRVWorldPosition();
301                float distance = ship.distance(endpoint_);
302                if(distance < 40)
303                {
304                    (*it)->destroy();
305                    enemies_.erase(it++);
306                    this->reduceLifes(1);
307                    if (this->getLifes() == 0)
308                    {
309                        this->end();
310                    }
311                }
312                else
313                {
314                    ++ it;
315                }
316            }
317        } 
318
319        // Add new enemy?
320        if (timeSinceLastSpawn_ >= 1.0 && waveSize_ > 0)
321        {
322            // Add new enemy
323            timeSinceLastSpawn_ -= 1.0;
324            -- waveSize_;
325            addTowerDefenseEnemy(this->getWaveNumber() % 3 + 1);
326        }
327        else if (timeUntilNextWave_ <= 0.0 && waveSize_ <= 0)
328        {
329            //New wave
330            ++ waveNumber_;
331            timeSinceLastSpawn_ = 0.0;
332
333            timeUntilNextWave_ = waveNumber_+20.0f;
334            waveSize_ = waveNumber_+5;
335        }
336
337    }
338
339    void TowerDefense::createFields()
340    {
341        assert(center_);
342        TDCoordinate coord(0,0);
343        TDCoordinate startCoord(0,0);
344        std::string fields = center_->getFields();
345        int pos = 0;
346        for (int j = 15; j >= 0; --j)
347        {
348            for (int i = 0; i < 16; ++i)
349            {
350                coord.Set(i,j);
351                fields_[i][j] = new TowerDefenseField(center_->getContext());
352                fields_[i][j]->setCenterpoint(center_);
353                center_->attach(fields_[i][j]);
354                fields_[i][j]->setPosition(coord.get3dcoordinate()); 
355                fields_[i][j]->create(fields.at(pos), fields.at(pos+1));
356                pos += 2;
357                if (fields_[i][j]->getType() == START)
358                {
359                    startCoord.Set(i,j);
360                    waypoints_.push_back(fields_[i][j]);
361                }
362            }
363        }
364        //Place waypoints along the street for the waypoint controllers of the enemies
365        TDCoordinate* thisCoord = &startCoord;
366        TDCoordinate* nextCoord;
367        while ((nextCoord = getNextStreetCoord(thisCoord)) != nullptr)
368        {
369            waypoints_.push_back(fields_[nextCoord->GetX()][nextCoord->GetY()]);           
370            thisCoord = nextCoord;
371            endpoint_ = nextCoord->get3dcoordinate();
372        }
373
374    }
375
376    TDCoordinate* TowerDefense::getNextStreetCoord(TDCoordinate* thisCoord)
377    {       
378        TowerDefenseField* thisField = fields_[thisCoord->GetX()][thisCoord->GetY()];
379        TDCoordinate* nextCoord = new TDCoordinate(0,0);
380
381        if (thisField->getType() != STREET && thisField->getType() != START)
382        {
383            return nullptr;
384        }
385
386        if (thisField->getAngle() == 0)
387        {
388            nextCoord->Set(thisCoord->GetX(), thisCoord->GetY() - 1);
389        }
390        else if (thisField->getAngle() == 1)
391        {
392            nextCoord->Set(thisCoord->GetX() + 1, thisCoord->GetY());
393        }
394        else if (thisField->getAngle() == 2)
395        {
396            nextCoord->Set(thisCoord->GetX(), thisCoord->GetY() + 1);
397        }
398        else if (thisField->getAngle() == 3)
399        {
400            nextCoord->Set(thisCoord->GetX() - 1, thisCoord->GetY());
401        }
402
403        if (thisCoord->GetX() != nextCoord->GetX() || thisCoord->GetY() != nextCoord->GetY())
404        {
405            return nextCoord;
406        }
407
408        return nullptr;
409    }
410}
Note: See TracBrowser for help on using the repository browser.