1 // Description:
2 //   Stage manager controls movement from levelpack to levelpack and
3 //   level to level.
4 //
5 // Copyright (C) 2001 Frank Becker
6 //
7 // This program is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU General Public License as published by the Free Software
9 // Foundation;  either version 2 of the License,  or (at your option) any  later
10 // version.
11 //
12 // This program is distributed in the hope that it will be useful,  but  WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
15 //
16 #include <Trace.hpp>
17 #include <Constants.hpp>
18 #include <GameState.hpp>
19 #include <StageManager.hpp>
20 #include <EnemyFactory.hpp>
21 #include <Skill.hpp>
22 #include <XMLHelper.hpp>
23 #include <Config.hpp>
24 #include <Hero.hpp>
25 
26 #include <Random.hpp>
27 #include <ParticleInfo.hpp>
28 #include <Particles.hpp>
29 #include <ParticleGroup.hpp>
30 #include <ParticleGroupManager.hpp>
31 
init(void)32 bool StageManager::init( void)
33 {
34     return findLevelPacks();
35 }
36 
reset(void)37 void StageManager::reset( void)
38 {
39     //catch used skill changes via runtime config
40     SkillS::instance()->updateSkill();
41 
42     _levelPackIterator = _levelPackList.begin();
43     loadNextLevelPack();
44     activateLevel();
45 }
46 
update(void)47 void StageManager::update( void)
48 {
49     static ParticleGroup *bonus =
50 	ParticleGroupManagerS::instance()->getParticleGroup( BONUS_GROUP);
51 
52     //no armor piercing needed for rookie
53     if( (GameState::skill != Skill::eRookie) &&
54         (HeroS::instance()->getArmorPierce() <= 1.0f))
55     {
56 	if( Random::rangef0_1() < 0.001f)
57 	{
58 	    LOG_INFO << "ArmorPierce" << endl;
59 	    float posX = (Random::rangef0_1()-0.5f) * 60.0f;
60 	    bonus->newParticle( "ArmorPierce", posX, 49.0f, -100.0f);
61 	}
62     }
63 
64     if( GameState::numObjects == 0)
65     {
66         if( _delayEndOfLevel-- > 0) return;
67 
68         _activeLevelIndex++;
69 	if( _activeLevelIndex >= _levelList.size())
70 	{
71 	    loadNextLevelPack();
72 	}
73         else
74         {
75             _activeLevel = _levelList[ _activeLevelIndex];
76         }
77 	activateLevel();
78     }
79 }
80 
findLevelPacks(void)81 bool StageManager::findLevelPacks( void)
82 {
83     list<string> rList;
84     ResourceManagerS::instance()->getResourceList( rList);
85 
86     list<string>::iterator i;
87     for( i=rList.begin(); i!=rList.end(); i++)
88     {
89 	string resourceName = *i;
90 
91 	string::size_type end = resourceName.length()-8; // strlen("Pack.xml")
92 	string::size_type find = resourceName.find("Pack.xml");
93 	if( (find!=string::npos) && (find==end))
94 	{
95 	    LOG_INFO << "Adding LevelPack [" << resourceName << "]" << endl;
96 	    _levelPackList.insert( _levelPackList.end(), resourceName);
97 	}
98     }
99 
100 
101     _levelPackIterator = _levelPackList.begin();
102 
103     bool foundSome = _levelPackIterator != _levelPackList.end();
104     if( !foundSome)
105     {
106 	LOG_WARNING << "No levelpacks found in resource file!" << endl;
107 	string defaultLevelPack = "levelpacks/CritterPack.xml";
108 	_levelPackList.insert( _levelPackList.end(), defaultLevelPack);
109     }
110 
111     return true;
112 }
113 
loadNextLevelPack(void)114 bool StageManager::loadNextLevelPack( void)
115 {
116     XTRACE();
117 
118     if( _levelPackIterator == _levelPackList.end())
119     {
120 	_levelPackIterator = _levelPackList.begin();
121 	//when we wrap around, increment skill
122 	SkillS::instance()->incrementSkill();
123     }
124 
125     delete _activeLevelPack;
126 
127     string levelPackName = *_levelPackIterator;
128     _activeLevelPack = XMLHelper::load( levelPackName);
129 
130     if( !_activeLevelPack)
131     {
132 	_activeLevel = 0;
133 	return false;
134     }
135 
136     TiXmlNode *levelPack = _activeLevelPack->FirstChild("LevelPack");
137 
138     _activeLevel = levelPack->ToElement()->FirstChild();
139     _levelList.clear();
140     while( _activeLevel)
141     {
142         _levelList.push_back(_activeLevel);
143         _activeLevel = _activeLevel->NextSibling();
144     }
145 
146     bool randomLevels = false;
147     ConfigS::instance()->getBoolean( "randomLevels", randomLevels);
148     if( randomLevels)
149     {
150         int levelCount = _levelList.size();
151         for( int i=0; i<levelCount*10; i++)
152         {
153             int r1 = Random::integer(levelCount);
154             int r2 = Random::integer(levelCount);
155             std::swap( _levelList[r1], _levelList[r2]);
156         }
157     }
158     _activeLevelIndex = 0;
159     _activeLevel = _levelList[_activeLevelIndex];
160 
161     //advance to next level pack
162     _levelPackIterator++;
163 
164     if( !_activeLevelPack)
165     {
166 	LOG_ERROR << "No level pack found!" << endl;
167 	return false;
168     }
169 
170     return true;
171 }
172 
activateLevel(void)173 bool StageManager::activateLevel( void)
174 {
175     XTRACE();
176 
177     if( !_activeLevel)
178     {
179 	return false;
180     }
181 
182     GameState::stopwatch.pause();
183 
184     TiXmlElement* levelNode = _activeLevel->ToElement();
185     _activeLevelName = levelNode->Attribute("Name");
186     LOG_INFO << "Level '" << _activeLevelName
187              << "' by " << levelNode->Attribute("Author") << endl;
188 
189     static ParticleGroup *effects =
190 	ParticleGroupManagerS::instance()->getParticleGroup( EFFECTS_GROUP2);
191     ParticleInfo pi;
192     pi.position.x =  0.0;
193     pi.position.y =  0.0;
194     pi.position.z =-50.0;
195     pi.text = _activeLevelName;
196 
197     pi.color.x = 1.0;
198     pi.color.y = 1.0;
199     pi.color.z = 1.0;
200 
201     pi.extra.y = 0.1f;
202     pi.extra.z = 0.1f;
203 
204     effects->newParticle( "StatusMessage", pi);
205 
206     GameState::numObjects = 0;
207     _levelStartTime = GameState::stopwatch.getTime();
208     _delayEndOfLevel = 60; //2 sec
209 
210     TiXmlNode *enemyNode = _activeLevel->FirstChild();
211     while( enemyNode)
212     {
213         EnemyFactory::createEnemy( enemyNode);
214 	enemyNode = enemyNode->NextSibling();
215     }
216 
217     GameState::startOfStep = Timer::getTime(); //get fresh start for other logic
218 
219     GameState::stopwatch.start();
220     LOG_INFO << "Starting game timer\n";
221 
222     return true;
223 }
224