Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/story_entities/game_world.cc @ 6374

Last change on this file since 6374 was 6374, checked in by patrick, 18 years ago

network: single player loads again, many changes in the function bodies of the loading code

File size: 17.7 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   co-programmer: Christian Meyer
14   co-programmer: Benjamin Grauer
15*/
16
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
18
19#include "game_world.h"
20
21#include "shell_command.h"
22#include "resource_manager.h"
23#include "state.h"
24
25#include "p_node.h"
26#include "world_entity.h"
27#include "player.h"
28#include "camera.h"
29#include "environment.h"
30#include "terrain.h"
31
32#include "test_entity.h"
33#include "terrain.h"
34#include "light.h"
35#include "load_param.h"
36#include "shell.h"
37
38#include "fast_factory.h"
39#include "animation_player.h"
40#include "particle_engine.h"
41#include "graphics_engine.h"
42#include "physics_engine.h"
43#include "fields.h"
44
45#include "md2Model.h"
46
47#include "glmenu_imagescreen.h"
48#include "game_loader.h"
49
50#include "animation3d.h"
51
52#include "substring.h"
53
54#include "factory.h"
55
56#include "weapons/projectile.h"
57#include "event_handler.h"
58#include "sound_engine.h"
59#include "ogg_player.h"
60
61#include "class_list.h"
62
63#include "cd_engine.h"
64#include "npcs/npc_test1.h"
65#include "shader.h"
66
67#include "playable.h"
68#include "network_manager.h"
69#include "playable.h"
70
71
72SHELL_COMMAND(speed, GameWorld, setSpeed);
73SHELL_COMMAND(togglePNodeVisibility, GameWorld, togglePNodeVisibility);
74SHELL_COMMAND(toggleBVVisibility, GameWorld, toggleBVVisibility);
75
76using namespace std;
77
78//! This creates a Factory to fabricate a GameWorld
79CREATE_FACTORY(GameWorld, CL_GAME_WORLD);
80
81
82
83GameWorld::GameWorld(const TiXmlElement* root)
84  : StoryEntity()
85{
86  this->setClassID(CL_GAME_WORLD, "GameWorld");
87  this->setName("Preloaded World - no name yet");
88
89  this->gameTime = 0.0f;
90  this->setSpeed(1.0f);
91  this->music = NULL;
92  this->shell = NULL;
93  this->localPlayer = NULL;
94  this->localCamera = NULL;
95
96  this->showPNodes = false;
97  this->showBV = false;
98
99  this->path = NULL;
100}
101
102/**
103 *  remove the GameWorld from memory
104 *
105 *  delete everything explicitly, that isn't contained in the parenting tree!
106 *  things contained in the tree are deleted automaticaly
107 */
108GameWorld::~GameWorld ()
109{
110  delete this->shell;
111  PRINTF(3)("GameWorld::~GameWorld() - deleting current world\n");
112
113  delete this->localPlayer;
114
115  // delete all the initialized Engines.
116  FastFactory::flushAll(true);
117  delete LightManager::getInstance();
118  delete ParticleEngine::getInstance();
119  delete AnimationPlayer::getInstance();
120  delete PhysicsEngine::getInstance();
121
122  // external engines initialized by the orxonox-class get deleted
123  SoundEngine::getInstance()->flushAllBuffers();
124  SoundEngine::getInstance()->flushAllSources();
125
126  if (State::getObjectManager() == &this->objectManager)
127    State::setObjectManager(NULL);
128  // erease everything that is left.
129  delete PNode::getNullParent();
130
131  //secondary cleanup of PNodes;
132  const std::list<BaseObject*>* nodeList = ClassList::getList(CL_PARENT_NODE);
133  if (nodeList != NULL)
134    while (!nodeList->empty())
135      delete nodeList->front();
136
137  Shader::suspendShader();
138
139  // unload the resources !!
140  ResourceManager::getInstance()->unloadAllByPriority(RP_LEVEL);
141}
142
143
144
145/**
146 * loads the parameters of a GameWorld from an XML-element
147 * @param root the XML-element to load from
148 */
149void GameWorld::loadParams(const TiXmlElement* root)
150{
151  PRINTF(4)("Creating a GameWorld\n");
152
153  LoadParam(root, "identifier", this, GameWorld, setStoryID)
154    .describe("Sets the StoryID of this world");
155
156  LoadParam(root, "nextid", this, GameWorld, setNextStoryID)
157    .describe("Sets the ID of the next world");
158
159  LoadParam(root, "path", this, GameWorld, setPath)
160    .describe("The Filename of this GameWorld (relative from the data-dir)");
161}
162
163
164/**
165 * this is executed just before load
166 *
167 * since the load function sometimes needs data, that has been initialized
168 * before the load and after the proceeding storyentity has finished
169*/
170ErrorMessage GameWorld::init()
171{
172  State::setObjectManager(&this->objectManager);
173  this->cycle = 0;
174
175  /* init the world interface */
176  this->shell = new Shell();
177
178  LightManager::getInstance();
179  PNode::getNullParent();
180
181  AnimationPlayer::getInstance(); // initializes the animationPlayer
182  ParticleEngine::getInstance();
183  PhysicsEngine::getInstance();
184
185  this->localCamera = new Camera();
186  this->localCamera->setName ("GameWorld-Camera");
187
188  State::setCamera(this->localCamera, this->localCamera->getTarget());
189
190  GraphicsEngine::getInstance()->displayFPS(true);
191}
192
193
194/**
195 *  loads the GameWorld by initializing all resources, and set their default values.
196 */
197ErrorMessage GameWorld::loadData()
198{
199  this->displayLoadScreen();
200
201  PRINTF(3)("> Loading world: '%s'\n", getPath());
202  TiXmlElement* element;
203  GameLoader* loader = GameLoader::getInstance();
204
205  if( getPath() == NULL)
206    {
207      PRINTF(1)("GameWorld has no path specified for loading");
208      return (ErrorMessage){213,"Path not specified","GameWorld::load()"};
209    }
210
211  TiXmlDocument* XMLDoc = new TiXmlDocument( getPath());
212  // load the campaign document
213  if( !XMLDoc->LoadFile())
214  {
215    // report an error
216    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getPath(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
217    delete XMLDoc;
218    return (ErrorMessage){213,"XML File parsing error","GameWorld::load()"};
219  }
220
221  // check basic validity
222  TiXmlElement* root = XMLDoc->RootElement();
223  assert( root != NULL);
224
225  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
226    {
227      // report an error
228      PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
229      delete XMLDoc;
230      return (ErrorMessage){213,"Path not a WorldDataFile","GameWorld::load()"};
231    }
232
233  // load the parameters
234  // name
235  const char* string = grabParameter( root, "name");
236  if( string == NULL)
237    {
238      PRINTF(2)("GameWorld is missing a proper 'name'\n");
239      this->setName("Unknown");
240    }
241  else
242    {
243      this->setName(string);
244    }
245
246  ////////////////
247  // LOADSCREEN //
248  ////////////////
249  element = root->FirstChildElement("LoadScreen");
250  if (element == NULL)
251    {
252      PRINTF(2)("no LoadScreen specified, loading default\n");
253
254      glmis->setBackgroundImage("pictures/load_screen.jpg");
255      this->glmis->setMaximum(8);
256      this->glmis->draw();
257    }
258  else
259    {
260      this->glmis->loadParams(element);
261      this->glmis->draw();
262    }
263  this->glmis->draw();
264
265  ////////////////////////
266  // find WorldEntities //
267  ////////////////////////
268
269  element = root->FirstChildElement("WorldEntities");
270
271  if( element == NULL)
272    {
273      PRINTF(1)("GameWorld is missing 'WorldEntities'\n");
274    }
275  else
276    {
277      element = element->FirstChildElement();
278      // load Players/Objects/Whatever
279      PRINTF(4)("Loading WorldEntities\n");
280      while( element != NULL)
281        {
282          BaseObject* created = Factory::fabricate(element);
283          if( created != NULL )
284          {
285            if(created->isA(CL_WORLD_ENTITY))
286              this->spawn(dynamic_cast<WorldEntity*>(created));
287            printf("Created a %s: %s\n", created->getClassName(), created->getName());
288          }
289
290          // if we load a 'Player' we use it as localPlayer
291
292
293          //todo do this more elegant
294          if( element->Value() != NULL && !strcmp( element->Value(), "SkyBox"))
295            this->sky = dynamic_cast<WorldEntity*>(created);
296          if( element->Value() != NULL && !strcmp( element->Value(), "Terrain"))
297          {
298            terrain = dynamic_cast<Terrain*>(created);
299            CDEngine::getInstance()->setTerrain(terrain);
300          }
301          element = element->NextSiblingElement();
302          glmis->step(); //! @todo temporary
303        }
304      PRINTF(4)("Done loading WorldEntities\n");
305    }
306
307    //////////////////////////////
308    // LOADING ADDITIONAL STUFF //
309    //////////////////////////////
310
311    LoadParamXML(root, "LightManager", LightManager::getInstance(), LightManager, loadParams);
312
313   LoadParamXML(root, "ParticleEngine", ParticleEngine::getInstance(), ParticleEngine, loadParams);
314//   LoadParamXML(root, "PhysicsEngine", PhysicsEngine::getInstance(), PhysicsEngine, loadParams);
315
316  // free the XML data
317
318  delete XMLDoc;
319  /* GENERIC LOADING PROCESS FINISHED */
320
321
322  // Create a Player
323  this->localPlayer = new Player();
324
325  Playable* playable;
326  const list<BaseObject*>* playableList = ClassList::getList(CL_PLAYABLE);
327  if (playableList != NULL)
328  {
329    playable = dynamic_cast<Playable*>(playableList->front());
330    this->localPlayer->setControllable(playable);
331  }
332
333
334//   //localCamera->setParent(TrackNode::getInstance());
335//  tn->addChild(this->localCamera);
336  localCamera->setClipRegion(1, 10000.0);
337//  localCamera->lookAt(playable);
338//  this->localPlayer->setParentMode(PNODE_ALL);
339  if (this->sky != NULL)
340  {
341    this->localCamera->addChild(sky);
342  }
343  SoundEngine::getInstance()->setListener(this->localCamera);
344
345  /* some static stuff*/
346
347  this->music = NULL;
348  //(OggPlayer*)ResourceManager::getInstance()->load("sound/00-luke_grey_-_hypermode.ogg", OGG, RP_LEVEL);
349  //music->playback();
350
351  this->releaseLoadScreen();
352}
353
354
355/**
356 *  initializes a new GameWorld shortly before start
357 *
358 * this is the function, that will be loaded shortly before the world is
359 * started
360*/
361ErrorMessage GameWorld::preStart()
362{
363  this->bPause = false;
364
365  /* update the object position before game start - so there are no wrong coordinates used in the first processing */
366  PNode::getNullParent()->updateNode (0.001f);
367  PNode::getNullParent()->updateNode (0.001f);
368}
369
370
371/**
372 *  starts the GameWorld
373 */
374ErrorMessage GameWorld::start()
375{
376  this->bQuitWorld = false;
377  this->mainLoop();
378}
379
380/**
381 *  stops the world.
382
383   This happens, when the player decides to end the Level.
384*/
385ErrorMessage GameWorld::stop()
386{
387  PRINTF(3)("GameWorld::stop() - got stop signal\n");
388  this->bQuitWorld= true;
389}
390
391/**
392 *  pauses the Game
393*/
394ErrorMessage GameWorld::pause()
395{
396  this->isPaused = true;
397}
398
399/**
400 *  ends the pause Phase
401*/
402ErrorMessage GameWorld::resume()
403{
404  this->isPaused = false;
405}
406
407
408/**
409 *  shows the loading screen
410*/
411void GameWorld::displayLoadScreen ()
412{
413  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
414
415  //GLMenuImageScreen*
416  this->glmis = new GLMenuImageScreen();
417  this->glmis->setMaximum(8);
418
419  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
420}
421
422/**
423 * @brief removes the loadscreen, and changes over to the game
424 *
425 * @todo take out the delay
426*/
427void GameWorld::releaseLoadScreen ()
428{
429  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
430  this->glmis->setValue(this->glmis->getMaximum());
431  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
432  delete this->glmis;
433}
434
435
436/**
437 *  synchronize local data with remote data
438*/
439void GameWorld::synchronize ()
440{
441  // Get remote input
442  // Update synchronizables
443/*  NetworkManager::getInstance()->synchronize();*/
444}
445
446
447/**
448 *  run all input processing
449
450   the command node is the central input event dispatcher. the node uses the even-queue from
451   sdl and has its own event-passing-queue.
452*/
453void GameWorld::handleInput ()
454{
455  EventHandler::getInstance()->process();
456
457  // remoteinput
458}
459
460void GameWorld::tick(std::list<WorldEntity*> entityList, float dt)
461{
462  std::list<WorldEntity*>::iterator entity;
463  for (entity = entityList.begin(); entity != entityList.end(); entity++)
464    (*entity)->tick(dt);
465
466}
467
468/**
469 *  advance the timeline
470
471   this calculates the time used to process one frame (with all input handling, drawing, etc)
472   the time is mesured in ms and passed to all world-entities and other classes that need
473   a heart-beat.
474*/
475void GameWorld::tick ()
476{
477  Uint32 currentFrame = SDL_GetTicks();
478  if(!this->bPause)
479    {
480      this->dt = currentFrame - this->lastFrame;
481
482      if( this->dt > 10)
483        {
484          float fps = 1000/dt;
485
486          // temporary, only for showing how fast the text-engine is
487          char tmpChar[20];
488          sprintf(tmpChar, "fps: %4.0f", fps);
489        }
490      else
491        {
492          /* the frame-rate is limited to 100 frames per second, all other things are for
493             nothing.
494          */
495          PRINTF(3)("fps = 1000 - frame rate is adjusted\n");
496          SDL_Delay(10-dt);
497          this->dt = 10;
498        }
499
500      this->dtS = (float)this->dt / 1000.0 * this->speed;
501      this->gameTime += this->dtS;
502
503      this->tick(this->objectManager.getObjectList(OM_DEAD_TICK), this->dtS);
504      this->tick(this->objectManager.getObjectList(OM_COMMON), this->dtS);
505      this->tick(this->objectManager.getObjectList(OM_GROUP_00), this->dtS);
506      this->tick(this->objectManager.getObjectList(OM_GROUP_01), this->dtS);
507      this->tick(this->objectManager.getObjectList(OM_GROUP_01_PROJ), this->dtS);
508
509      /* update tick the rest */
510      this->localCamera->tick(this->dtS);
511      // tick the engines
512      AnimationPlayer::getInstance()->tick(this->dtS);
513//      if (this->cycle > 5)
514        PhysicsEngine::getInstance()->tick(this->dtS);
515
516      ParticleEngine::getInstance()->tick(this->dtS);
517
518
519      /** actualy the Graphics Engine should tick the world not the other way around...
520         but since we like the things not too complicated we got it this way around
521         until there is need or time to do it the other way around.
522         @todo: GraphicsEngine ticks world: separation of processes and data...
523
524        bensch: in my opinion the GraphicsEngine could draw the world, but not tick it,
525         beceause graphics have nothing(or at least not much) to do with Motion.
526      */
527      GraphicsEngine::getInstance()->tick(this->dtS);
528    }
529  this->lastFrame = currentFrame;
530}
531
532
533/**
534 *  this function gives the world a consistant state
535
536   after ticking (updating the world state) this will give a constistant
537   state to the whole system.
538*/
539void GameWorld::update()
540{
541  GraphicsEngine::getInstance()->update(this->dtS);
542  PNode::getNullParent()->updateNode (this->dtS);
543  SoundEngine::getInstance()->update();
544  //music->update();
545}
546
547
548void GameWorld::collide()
549{
550  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_00),
551                                            this->objectManager.getObjectList(OM_GROUP_01_PROJ));
552  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_01),
553                                            this->objectManager.getObjectList(OM_COMMON));
554}
555
556/**
557 *  render the current frame
558
559   clear all buffers and draw the world
560*/
561void GameWorld::display ()
562{
563  // clear buffer
564  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
565  // set camera
566  this->localCamera->apply ();
567  // draw world
568  this->draw();
569  // draw HUD
570  /** @todo draw HUD */
571  // flip buffers
572  GraphicsEngine::swapBuffers();
573  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
574  //SDL_Flip (screen);
575}
576
577
578/**
579 *  runs through all entities calling their draw() methods
580 */
581void GameWorld::draw ()
582{
583  GraphicsEngine* engine = GraphicsEngine::getInstance();
584  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
585  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON));
586  engine->draw(State::getObjectManager()->getObjectList(OM_COMMON));
587  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_00));
588  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01));
589  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
590
591   if( unlikely( this->showBV))  // to draw the bounding boxes of the objects at level 2 for debug purp
592   {
593     CDEngine* engine = CDEngine::getInstance();
594     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
595     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON));
596     engine->drawBV(State::getObjectManager()->getObjectList(OM_COMMON));
597     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_00));
598     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01));
599     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
600   }
601
602//   {
603//     if( entity->isVisible() ) entity->draw();
604  //FIXME
605//     entity = iterator->nextElement();
606//   }
607
608  ParticleEngine::getInstance()->draw();
609
610  if (unlikely(this->showPNodes))
611    PNode::getNullParent()->debugDraw(0);
612
613  engine->draw();
614  //TextEngine::getInstance()->draw();
615}
616
617
618/**
619 * \brief main loop of the world: executing all world relevant function
620 *
621 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
622 * all other member-entities of the world (tick to player, enemies etc.), checking for
623 * collisions drawing everything to the screen.
624 */
625void GameWorld::mainLoop()
626{
627  this->lastFrame = SDL_GetTicks ();
628  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
629
630  while(!this->bQuitWorld) /* @todo implement pause */
631  {
632    ++this->cycle;
633      // Network
634    this->synchronize ();
635      // Process input
636    this->handleInput ();
637    if( this->bQuitWorld)
638      break;
639      // Process time
640    this->tick ();
641      // Process collision
642    this->collide ();
643      // Update the state
644    this->update ();
645      // Draw
646    this->display ();
647  }
648
649  PRINTF(3)("GameWorld::mainLoop() - Exiting the main loop\n");
650}
651
652
653
654/**
655 *  add and spawn a new entity to this world
656 * @param entity to be added
657*/
658void GameWorld::spawn(WorldEntity* entity)
659{
660//   this->entities->add (entity);
661  entity->postSpawn ();
662}
663
664/**
665 *  sets the track path of this world
666 * @param name the name of the path
667 */
668void GameWorld::setPath( const char* name)
669{
670  if (this->path)
671    delete this->path;
672  if (ResourceManager::isFile(name))
673  {
674    this->path = new char[strlen(name)+1];
675    strcpy(this->path, name);
676  }
677  else
678    {
679      this->path = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(name) +1];
680      sprintf(this->path, "%s%s", ResourceManager::getInstance()->getDataDir(), name);
681    }
682}
683
Note: See TracBrowser for help on using the repository browser.