Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/cleanup/src/story_entities/game_world.cc @ 10585

Last change on this file since 10585 was 10585, checked in by snellen, 17 years ago

Removed classes Account and Object (both needed only to test the scriptingframework)and removed example.cc, cleaned commented code in script_trigger.cc and gameworld.cc. … more to come

File size: 19.3 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13   main-programmer: Benjamin Grauer
14   co-programmer: Christian Meyer
15
16*/
17
18#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
19
20#include "game_world.h"
21#include "game_world_data.h"
22
23#include "state.h"
24
25#include "util/loading/game_loader.h"
26#include "util/timer.h"
27
28#include "player.h"
29#include "camera.h"
30#include "environment.h"
31#include "terrain.h"
32#include "test_entity.h"
33#include "terrain.h"
34#include "playable.h"
35#include "environments/mapped_water.h"
36
37#include "light.h"
38
39#include "util/loading/factory.h"
40#include "util/loading/load_param_xml.h"
41#include "loading/fast_factory.h"
42#include "shell_command.h"
43
44#include "graphics_engine.h"
45#include "weather_effects/atmospheric_engine.h"
46#include "event_handler.h"
47#include "sound_engine.h"
48#include "cd_engine.h"
49#include "network_manager.h"
50#include "physics_engine.h"
51
52#include "glmenu_imagescreen.h"
53#include "shell.h"
54
55#include "ogg_player.h"
56#include "shader.h"
57#include "ai_engine.h"
58
59#include "animation_player.h"
60
61#include "game_rules.h"
62
63#include "script_class.h"
64ObjectListDefinition(GameWorld);
65CREATE_SCRIPTABLE_CLASS(GameWorld,
66                        addMethod("setPlaymode", Executor1<GameWorld, lua_State*,const std::string&>(&GameWorld::setPlaymode))
67                        ->addMethod("showText", Executor1<GameWorld, lua_State*, const std::string&>(&GameWorld::showText))
68                        ->addMethod("setSoundtrack", Executor1<GameWorld, lua_State*, const std::string&>(&GameWorld::setSoundtrack))
69                        ->addMethod("getStoryID", Executor0ret<StoryEntity, lua_State*, int>(&StoryEntity::getStoryID))
70                        ->addMethod("setNextStoryName", Executor1ret<StoryEntity, lua_State*, bool, const std::string&>(&StoryEntity::setNextStoryName))
71                        ->addMethod("stop", Executor0ret<GameWorld, lua_State*, bool>(&GameWorld::stop))
72                       );
73
74SHELL_COMMAND(speed, GameWorld, setSpeed) ->describe("set the Speed of the Level");
75SHELL_COMMAND(playmode, GameWorld, setPlaymode)
76->describe("Set the Playmode of the current Level")
77->completionPlugin(0, OrxShell::CompletorStringArray(Playable::playmodeNames, Playable::PlaymodeCount));
78
79SHELL_COMMAND(togglePNodeVisibility, GameWorld, togglePNodeVisibility);
80SHELL_COMMAND(showBVLevel, GameWorld, toggleBVVisibility);
81SHELL_COMMAND(showMountPoints, GameWorld, toggleMPVisibility);
82
83
84GameWorld::GameWorld()
85    : StoryEntity()
86{
87  this->registerObject(this, GameWorld::_objectList);
88  this->setName("Preloaded World - no name yet");
89
90  this->gameTime = 0.0f;
91  this->setSpeed(1.0f);
92  this->shell = NULL;
93
94  this->showPNodes = false;
95  this->showBV = false;
96  this->showBVLevel = 3;
97  this->showMPV = false;
98
99  this->dataXML = NULL;
100  this->gameRules = NULL;
101}
102
103/**
104 *  remove the GameWorld from memory
105 *
106 *  delete everything explicitly, that isn't contained in the parenting tree!
107 *  things contained in the tree are deleted automaticaly
108 */
109GameWorld::~GameWorld ()
110{
111  PRINTF(4)("Deleted GameWorld\n");
112
113}
114
115
116
117/**
118 * loads the parameters of a GameWorld from an XML-element
119 * @param root the XML-element to load from
120 */
121void GameWorld::loadParams(const TiXmlElement* root)
122{
123  StoryEntity::loadParams(root);
124
125  PRINTF(4)("Loaded GameWorld specific stuff\n");
126}
127
128
129/**
130 * this is executed just before load
131 *
132 * since the load function sometimes needs data, that has been initialized
133 * before the load and after the proceeding storyentity has finished
134*/
135ErrorMessage GameWorld::init()
136{
137  /* init the world interface */
138  this->shell = new OrxShell::Shell();
139
140  State::setCurrentStoryEntity(dynamic_cast<StoryEntity*>(this));
141  this->dataTank->init();
142
143  /* initialize some engines and graphical elements */
144  AnimationPlayer::getInstance();
145  PhysicsEngine::getInstance();
146  CoRe::CREngine::getInstance();
147
148  State::setScriptManager(&this->scriptManager);
149
150  return ErrorMessage();
151}
152
153/**
154 *  loads the GameWorld by initializing all resources, and set their default values.
155 */
156ErrorMessage GameWorld::loadData()
157{
158  this->displayLoadScreen();  State::setScriptManager(&this->scriptManager);
159
160
161  PRINTF(4)("Loading the GameWorld\n");
162
163  PRINTF(3)("> Loading world: '%s'\n", getLoadFile().c_str());
164  //  TiXmlElement* element;
165  //  GameLoader* loader = GameLoader::getInstance();
166
167  if( getLoadFile().empty())
168  {
169    PRINTF(1)("GameWorld has no path specified for loading\n");
170    return (ErrorMessage(213,"Path not specified","GameWorld::load()"));
171  }
172
173  TiXmlDocument* XMLDoc = new TiXmlDocument( getLoadFile());
174  // load the xml world file for further loading
175  if( !XMLDoc->LoadFile())
176  {
177    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getLoadFile().c_str(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
178    delete XMLDoc;
179    return ErrorMessage(213,"XML File parsing error","GameWorld::load()");
180  }
181  // check basic validity
182  TiXmlElement* root = XMLDoc->RootElement();
183  assert( root != NULL);
184  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
185  {
186    // report an error
187    PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
188    delete XMLDoc;
189    return ErrorMessage(213,"Path not a WorldDataFile","GameWorld::load()");
190  }
191  /* the whole loading process for the GameWorld */
192  this->dataTank->loadData(root);
193  this->dataXML = (TiXmlElement*)root->Clone();
194
195  LoadParamXML(root, "ScriptManager", &this->scriptManager, ScriptManager, loadParams);
196
197  delete XMLDoc;
198  this->releaseLoadScreen();
199
200  return ErrorMessage();
201}
202
203
204/**
205 *  unload the data of this GameWorld
206 */
207ErrorMessage GameWorld::unloadData()
208{
209
210  PRINTF(3)("GameWorld::~GameWorld() - unloading the current GameWorld\n");
211  this->scriptManager.flush();
212
213  delete this->shell;
214
215  this->dataTank->unloadData();
216
217  this->shell = NULL;
218  delete AnimationPlayer::getInstance();
219  delete PhysicsEngine::getInstance();
220  delete CoRe::CREngine::getInstance();
221
222  State::setCurrentStoryEntity(NULL);
223  if (this->dataXML)
224    delete this->dataXML;
225
226  return ErrorMessage();
227}
228
229
230void GameWorld::setSoundtrack(const std::string& soundTrack)
231{
232  if (this->dataTank != NULL)
233  {
234    this->dataTank->setSoundTrack(soundTrack);
235    this->dataTank->music->play();
236  }
237}
238
239void GameWorld::showText(const std::string& text)
240{
241  if ( this->dataTank->localPlayer != NULL)
242    this->dataTank->localPlayer->hud().notifyUser(text);
243}
244
245
246/**
247 *  starts the GameWorld
248 */
249bool GameWorld::start()
250{
251  this->bPaused = false;
252  this->bRunning = true;
253  State::setScriptManager(&this->scriptManager); //make sure we have the right script manager
254  this->run();
255
256  return true;
257}
258
259
260/**
261 *  stops the world.
262 */
263bool GameWorld::stop()
264{
265  PRINTF(3)("GameWorld::stop() - got stop signal\n");
266  State::setScriptManager(NULL);
267  return (this->bRunning = false);
268}
269
270
271/**
272 *  pauses the game
273 */
274bool GameWorld::pause()
275{
276  return (this->bPaused = true);
277}
278
279
280/**
281 *  ends the pause Phase
282 */
283bool GameWorld::resume()
284{
285  return(this->bPaused = false);
286}
287
288
289/**
290 *  main loop of the world: executing all world relevant function
291 *
292 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
293 * all other member-entities of the world (tick to player, enemies etc.), checking for
294 * collisions drawing everything to the screen.
295 */
296void GameWorld::run()
297{
298  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
299
300  // initialize Timing
301  this->cycle = 0;
302  for (unsigned int i = 0; i < TICK_SMOOTH_VALUE; i++)
303    this->frameTimes[i] = 0.01f;
304  this->dtS = 0.0f;
305  this->lastFrame = Timer::getNow();
306
307  if (this->dataTank->music != NULL)
308    this->dataTank->music->play();
309
310  PNode::getNullParent()->updateNode(0.01);
311  PNode::getNullParent()->updateNode(0.01);
312
313  bool bNoDraw = true;
314
315  while( this->bRunning) /* @todo implement pause */
316  {
317    /* process intput */
318    this->handleInput ();
319    if( !this->bRunning)
320      break;
321
322    /* network synchronisation */
323    this->synchronize ();
324
325         /* perform ai check*/
326         this->checkAI();
327
328         this->update ();
329    /* process time */
330    this->tick ();
331
332
333    /* update the state */
334    //this->update (); /// LESS REDUNDANCY.
335    //      PNode::getNullParent()->updateNode(this->dtS);
336    PNode::getNullParent()->updateNode(this->dtS);
337
338    /* collision detection */
339    this->collisionDetection ();
340    /* collision reaction */
341    this->collisionReaction ();
342
343    /* check the game rules */
344    this->checkGameRules();
345
346    /* update the state */
347    this->update ();
348    /* draw everything */
349    if( bNoDraw)
350      this->display ();
351
352    bNoDraw= !bNoDraw;
353  }
354
355  PRINTF(4)("GameWorld::mainLoop() - Exiting the main loop\n");
356}
357
358
359void GameWorld::setPlaymode(Playable::Playmode playmode)
360{
361  if (this->dataTank->localPlayer &&
362      this->dataTank->localPlayer->getPlayable() &&
363      this->dataTank->localPlayer->getPlayable()->setPlaymode(playmode))
364  {
365    PRINTF(0)("Set Playmode to %d:%s\n", playmode, Playable::playmodeToString(playmode).c_str());
366  }
367  else
368  {
369    PRINTF(0)("Unable to set Playmode %d:'%s'\n", playmode, Playable::playmodeToString(playmode).c_str());
370  }
371}
372
373void GameWorld::setPlaymode(const std::string& playmode)
374{
375  this->setPlaymode(Playable::stringToPlaymode(playmode));
376}
377
378/**
379 *  synchronize local data with remote data
380*/
381void GameWorld::synchronize ()
382{}
383
384
385/**
386 *  run all input processing
387
388   the command node is the central input event dispatcher. the node uses the even-queue from
389   sdl and has its own event-passing-queue.
390*/
391void GameWorld::handleInput ()
392{
393  EventHandler::getInstance()->process();
394}
395
396
397/**
398 * @brief ticks a WorldEntity list
399 * @param entityList list of the WorldEntities
400 * @param dt time passed since last frame
401 */
402void GameWorld::tick(ObjectManager::EntityList entityList, float dt)
403{
404  ObjectManager::EntityList::iterator entity, next;
405  next = entityList.begin();
406  while (next != entityList.end())
407  {
408    entity = next++;
409    (*entity)->tick(dt);
410  }
411}
412
413
414/**
415 *  advance the timeline
416 *
417 * this calculates the time used to process one frame (with all input handling, drawing, etc)
418 * the time is mesured in ms and passed to all world-entities and other classes that need
419 * a heart-beat.
420 */
421void GameWorld::tick ()
422{
423  if( !this->bPaused)
424  {
425    // CALCULATE FRAMERATE
426    Uint32 frameTimesIndex;
427    Uint32 i;
428    double currentFrame = Timer::getNow();
429
430    if (currentFrame - this->lastFrame < .01)
431    {
432      SDL_Delay((int)(1000.0 * (0.01 - (currentFrame - lastFrame))));
433      currentFrame = Timer::getNow();
434    }
435
436
437    frameTimesIndex = this->cycle % TICK_SMOOTH_VALUE;
438    this->frameTimes[frameTimesIndex] = currentFrame - this->lastFrame;
439    this->lastFrame = currentFrame;
440    ++this->cycle;
441    this->dtS = 0.0;
442    for (i = 0; i < TICK_SMOOTH_VALUE; i++)
443      this->dtS += this->frameTimes[i];
444    this->dtS = this->dtS / TICK_SMOOTH_VALUE * speed;
445
446    // tick camera first
447    CameraMan* man = State::getCameraman();
448    (man->getCurrentCam())->tick(this->dtS);
449    // TICK everything
450    for (i = 0; i < this->dataTank->tickLists.size(); ++i)
451      this->tick(this->dataTank->objectManager->getEntityList(this->dataTank->tickLists[i]), this->dtS);
452
453    /* update tick the rest */
454
455    AnimationPlayer::getInstance()->tick(this->dtS);
456    PhysicsEngine::getInstance()->tick(this->dtS);
457
458    GraphicsEngine::getInstance()->tick(this->dtS);
459    AtmosphericEngine::getInstance()->tick(this->dtS);
460
461    if( likely(this->dataTank->gameRule != NULL))
462      this->dataTank->gameRule->tick(this->dtS);
463
464  }
465}
466
467
468/**
469 *  this function gives the world a consistant state
470 *
471 * after ticking (updating the world state) this will give a constistant
472 * state to the whole system.
473 */
474void GameWorld::update()
475{
476  PNode::getNullParent()->updateNode (this->dtS);
477  OrxSound::SoundEngine::getInstance()->update();
478
479  this->applyCameraSettings();
480  GraphicsEngine::getInstance()->update(this->dtS);
481}
482
483
484/**
485 * kicks the CDEngine to detect the collisions between the object groups in the world
486 */
487void GameWorld::collisionDetection()
488{
489  // object-object collision detection
490  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_00),
491      this->dataTank->objectManager->getEntityList(OM_GROUP_01_PROJ));
492  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
493      this->dataTank->objectManager->getEntityList(OM_GROUP_00_PROJ));
494  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
495      this->dataTank->objectManager->getEntityList(OM_GROUP_00));
496
497  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
498      this->dataTank->objectManager->getEntityList(OM_GROUP_02));
499  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_02),
500      this->dataTank->objectManager->getEntityList(OM_GROUP_01_PROJ));
501
502
503  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_00),
504      this->dataTank->objectManager->getEntityList(OM_COMMON));
505  CDEngine::getInstance()->checkCollisions(this->dataTank->objectManager->getEntityList(OM_GROUP_01),
506      this->dataTank->objectManager->getEntityList(OM_COMMON));
507
508  // ground collision detection: BSP Model
509  CDEngine::getInstance()->checkCollisionGround(this->dataTank->objectManager->getEntityList(OM_GROUP_00));
510  CDEngine::getInstance()->checkCollisionGround(this->dataTank->objectManager->getEntityList(OM_GROUP_01));
511}
512
513
514void GameWorld::collisionReaction()
515{
516  CoRe::CREngine::getInstance()->handleCollisions();
517}
518
519
520
521void GameWorld::checkAI()
522{
523  AIEngine::getInstance()->tick(this->dtS);
524  //AIEngine::getInstance()->tick();
525}
526
527
528/**
529 *  check the game rules: winning conditions, etc.
530 *
531 */
532void GameWorld::checkGameRules()
533{
534  if( this->gameRules)
535    this->gameRules->tick(this->dtS);
536}
537
538
539/**
540 *  render the current frame
541 *
542 * clear all buffers and draw the world
543 */
544void GameWorld::display ()
545{
546
547  // if this server is a dedicated server the game workd does not need to be drawn
548  if( !GraphicsEngine::getInstance()->isDedicated())
549  {
550    // render the reflection texture
551    this->renderPassReflection();
552    // redner the refraction texture
553    this->renderPassRefraction();
554  }
555  // render all
556  this->renderPassAll();
557
558  // flip buffers
559  GraphicsEngine::swapBuffers();
560}
561
562
563/**
564 * @brief draws all entities in the list drawList
565 * @param drawList the List of entities to draw.
566 */
567void GameWorld::drawEntityList(const ObjectManager::EntityList& drawList) const
568{
569  ObjectManager::EntityList::const_iterator entity;
570  for (entity = drawList.begin(); entity != drawList.end(); entity++)
571  {
572    if ((*entity)->isVisible())
573      (*entity)->draw();
574
575    if( unlikely( this->showMPV))
576      (*entity)->debugDrawMountPoints();
577  }
578}
579
580
581void GameWorld::applyCameraSettings()
582{
583  CameraMan* man = State::getCameraman();
584  Camera* c = man->getCurrentCam();
585  if( c != NULL)
586  {
587    c->apply ();
588    c->project ();
589  }
590  GraphicsEngine::storeMatrices();
591}
592
593
594
595/**
596 * reflection rendering for water surfaces
597 */
598void GameWorld::renderPassReflection()
599{
600  // clear buffer
601  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
602  //  glLoadIdentity();
603
604  MappedWater* mw;
605
606  for (ObjectList<MappedWater>::const_iterator it = MappedWater::objectList().begin();
607       it != MappedWater::objectList().end();
608       ++it)
609  {
610    mw =  (*it);
611
612    //camera and light
613    //this->dataTank->localCamera->apply ();
614    //this->dataTank->localCamera->project ();
615
616    LightManager::getInstance()->draw();
617
618
619    // prepare for reflection rendering
620    mw->activateReflection();
621
622    // draw everything to be included in the reflection
623    this->drawEntityList(State::getObjectManager()->getReflectionList());
624    //       for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
625    //         this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
626
627    // clean up from reflection rendering
628    mw->deactivateReflection();
629  }
630
631}
632
633
634/**
635 *  refraction rendering for water surfaces
636 */
637void GameWorld::renderPassRefraction()
638{
639  // clear buffer
640  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
641  //glLoadIdentity();
642
643  MappedWater* mw;
644
645  for (ObjectList<MappedWater>::const_iterator it = MappedWater::objectList().begin();
646       it != MappedWater::objectList().end();
647       ++it)
648  {
649    mw =  dynamic_cast<MappedWater*>(*it);
650
651    //camera and light
652    //this->dataTank->localCamera->apply ();
653    //this->dataTank->localCamera->project ();
654    // prepare for reflection rendering
655    mw->activateRefraction();
656
657
658    LightManager::getInstance()->draw();
659    // draw everything to be included in the reflection
660    this->drawEntityList(State::getObjectManager()->getReflectionList());
661    //       for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
662    //         this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
663
664    // clean up from reflection rendering
665    mw->deactivateRefraction();
666  }
667}
668
669
670/**
671 *  this render pass renders the whole wolrd
672 */
673void GameWorld::renderPassAll()
674{
675  // clear buffer
676  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
677  GraphicsEngine* engine = GraphicsEngine::getInstance();
678
679
680  // glEnable(GL_DEPTH_TEST);
681  // glEnable(GL_LIGHTING);
682
683  // set Lighting
684  LightManager::getInstance()->draw();
685
686  // only render the world if its not dedicated mode
687  if( !GraphicsEngine::getInstance()->isDedicated())
688  {
689    /* Draw the BackGround */
690    this->drawEntityList(State::getObjectManager()->getEntityList(OM_BACKGROUND));
691    engine->drawBackgroundElements();
692
693    /* draw all WorldEntiy groups */
694    for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
695      this->drawEntityList(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]));
696
697    AtmosphericEngine::getInstance()->draw();
698
699    if( unlikely( this->showBV))
700    {
701      CDEngine* engine = CDEngine::getInstance();
702      for (unsigned int i = 0; i < this->dataTank->drawLists.size(); ++i)
703        engine->drawBV(State::getObjectManager()->getEntityList(this->dataTank->drawLists[i]), this->showBVLevel);
704    }
705
706
707    if( unlikely(this->showPNodes))
708      PNode::getNullParent()->debugDraw(0);
709
710    // draw the game ruls
711    if( likely(this->dataTank->gameRule != NULL))
712      this->dataTank->gameRule->draw();
713  }
714
715  engine->draw();
716}
717
718
719/**
720 *  shows the loading screen
721 */
722void GameWorld::displayLoadScreen ()
723{
724  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
725  this->dataTank->glmis = new GLMenuImageScreen();
726  this->dataTank->glmis->setMaximum(8);
727  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
728}
729
730
731/**
732 *  removes the loadscreen, and changes over to the game
733 */
734void GameWorld::releaseLoadScreen()
735{
736  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
737  this->dataTank->glmis->setValue(this->dataTank->glmis->getMaximum());
738  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
739}
740
741
742
743/**
744 * @brief toggles the PNode visibility in the world (drawn as boxes)
745 */
746void GameWorld::togglePNodeVisibility()
747{
748  this->showPNodes = !this->showPNodes;
749};
750
751
752/**
753 * @brief toggles the bounding volume (BV) visibility
754*/
755void GameWorld::toggleBVVisibility(int level)
756{
757  if( level < 1)
758    this->showBV = false;
759  else
760  {
761    this->showBV = true;
762    this->showBVLevel = level;
763  }
764
765};
766
Note: See TracBrowser for help on using the repository browser.