Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

network: major changes in the world files

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