/[glob2]/glob2/src/Engine.cpp
ViewVC logotype

Contents of /glob2/src/Engine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.138 - (show annotations) (download)
Thu Jan 20 21:06:40 2005 UTC (19 years, 4 months ago) by nct
Branch: MAIN
CVS Tags: alpha12, alpha13, alpha14, alpha15
Branch point for: newgfxbackend, map-rewrite
Changes since 1.137: +11 -2 lines
Adjusted the timing ticks to delay, taking into account the 10ms resolution of SDL_delay(). +nuage

1 /*
2 Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière
3 for any question or comment contact us at nct@ysagoon.com or nuage@ysagoon.com
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #ifdef DX9_BACKEND
21 #include <Types.h>
22 #endif
23
24 #include <FileManager.h>
25 #include <GraphicContext.h>
26 #include <StringTable.h>
27 #include <Toolkit.h>
28 #include <Stream.h>
29 #include <BinaryStream.h>
30
31 #include "CustomGameScreen.h"
32 #include "EndGameScreen.h"
33 #include "Engine.h"
34 #include "Game.h"
35 #include "GlobalContainer.h"
36 #include "LogFileManager.h"
37 #include "MultiplayersHostScreen.h"
38 #include "MultiplayersJoinScreen.h"
39 #include "MultiplayersChooseMapScreen.h"
40 #include "NetGame.h"
41 #include "Utilities.h"
42 #include "YOGScreen.h"
43 #include "SoundMixer.h"
44 #include "CampaignScreen.h"
45 #include <iostream>
46
47
48 Engine::Engine()
49 {
50 net=NULL;
51 for (int i=0; i<=40; i++)
52 cpuStats[i]=0;
53 logFile = globalContainer->logFileManager->getFile("Engine.log");
54 }
55
56 Engine::~Engine()
57 {
58 fprintf(logFile, "cpu usage stats:\n");
59 for (int i=0; i<=40; i++)
60 fprintf(logFile, "%3d.%1d %% = %d\n", 100-(i*5)/2, (i&1)*5, cpuStats[i]);
61 int sum=0;
62 for (int i=0; i<=40; i++)
63 sum+=cpuStats[i];
64 fprintf(logFile, "\n");
65 fprintf(logFile, "cpu usage graph:\n");
66 for (int i=0; i<=40; i++)
67 {
68 fprintf(logFile, "%3d.%1d %% | ", 100-(i*5)/2, (i&1)*5);
69 double ratio=100.*(double)cpuStats[i]/(double)sum;
70 int jmax=(int)(ratio+0.5);
71 for (int j=0; j<jmax; j++)
72 fprintf(logFile, "*");
73 fprintf(logFile, "\n");
74 }
75
76 if (net)
77 {
78 delete net;
79 net=NULL;
80 }
81 }
82
83 int Engine::initCampaign()
84 {
85 ChooseMapScreen loadCampaignScreen("campaigns", "map", true);;
86 int lgs = loadCampaignScreen.execute(globalContainer->gfx, 40);
87 if (lgs == ChooseMapScreen::CANCEL)
88 return EE_CANCEL;
89
90 return initCampaign(glob2NameToFilename("campaigns", loadCampaignScreen.sessionInfo.getMapNameC(), "map"));
91 }
92
93 int Engine::initCampaign(const std::string &mapName)
94 {
95 if (!loadGame(mapName))
96 return EE_CANT_LOAD_MAP;
97
98 // we make a player for each team
99 int playerNumber=0;
100 bool wasHuman=false;
101 char name[BasePlayer::MAX_NAME_LENGTH];
102 for (int i=0; i<gui.game.session.numberOfTeam; i++)
103 {
104 if (gui.game.teams[i]->type==BaseTeam::T_AI)
105 {
106 snprintf(name, BasePlayer::MAX_NAME_LENGTH, "AI Player %d", playerNumber);
107 gui.game.players[playerNumber]=new Player(playerNumber, name, gui.game.teams[i], BasePlayer::P_AI);
108 }
109 else if (gui.game.teams[i]->type==BaseTeam::T_HUMAN)
110 {
111 if (!wasHuman)
112 {
113 gui.localPlayer=playerNumber;
114 gui.localTeamNo=i;
115 snprintf(name, BasePlayer::MAX_NAME_LENGTH, "Player %d", playerNumber);
116 wasHuman=true;
117 gui.game.players[playerNumber]=new Player(playerNumber, name, gui.game.teams[i], BasePlayer::P_LOCAL);
118 }
119 else
120 {
121 snprintf(name, BasePlayer::MAX_NAME_LENGTH, "AI Player %d", playerNumber);
122 gui.game.players[playerNumber]=new Player(playerNumber, name, gui.game.teams[i], BasePlayer::P_AI);
123 }
124 }
125 else
126 assert(false);
127 gui.game.teams[i]->numberOfPlayer=1;
128 gui.game.teams[i]->playersMask=(1<<playerNumber);
129 playerNumber++;
130 }
131
132 if (!wasHuman)
133 {
134 std::cerr << " Engine::initCampaign(\"" << mapName << "\") : error, can't find any human player" << std::endl;
135 return EE_CANT_FIND_PLAYER;
136 }
137
138 gui.game.session.numberOfPlayer=playerNumber;
139
140 // if this is a campaign, show a screen
141 if (gui.game.campaignText.length() > 0)
142 {
143 CampaignScreen campaignScreen(gui.game.campaignText);
144 campaignScreen.execute(globalContainer->gfx, 40);
145 }
146
147 // We do some cosmetic fix
148 finalAdjustements();
149
150 // we create the net game
151 net=new NetGame(NULL, gui.game.session.numberOfPlayer, gui.game.players);
152
153 return EE_NO_ERROR;
154 }
155
156 int Engine::initCustom(void)
157 {
158 CustomGameScreen customGameScreen;
159
160 int cgs=customGameScreen.execute(globalContainer->gfx, 40);
161
162 if (cgs==CustomGameScreen::CANCEL)
163 return EE_CANCEL;
164 if (cgs==-1)
165 return -1;
166
167 if (!gui.loadBase(&(customGameScreen.sessionInfo)))
168 {
169 printf("Engine : Can't load map\n");
170 return EE_CANCEL;
171 }
172 int nbTeam=gui.game.session.numberOfTeam;
173 if (nbTeam==0)
174 return EE_CANCEL;
175
176 char name[BasePlayer::MAX_NAME_LENGTH];
177 int i;
178 int nbPlayer=0;
179
180 for (i=0; i<16; i++)
181 {
182 if (customGameScreen.isAIactive(i))
183 {
184 int teamColor=customGameScreen.getSelectedColor(i);
185 if (i==0)
186 {
187 gui.game.players[nbPlayer]=new Player(0, globalContainer->getUsername(), gui.game.teams[teamColor], BasePlayer::P_LOCAL);
188 gui.localPlayer=nbPlayer;
189 gui.localTeamNo=teamColor;
190 }
191 else
192 {
193 AI::ImplementitionID iid=customGameScreen.getAiImplementation(i);
194 snprintf(name, BasePlayer::MAX_NAME_LENGTH, "%s %d", Toolkit::getStringTable()->getString("[AI]", iid), nbPlayer-1);
195 gui.game.players[nbPlayer]=new Player(i, name, gui.game.teams[teamColor], Player::playerTypeFromImplementitionID(iid));
196 }
197 gui.game.teams[teamColor]->numberOfPlayer++;
198 gui.game.teams[teamColor]->playersMask|=(1<<nbPlayer);
199 nbPlayer++;
200 }
201 }
202 gui.game.session.numberOfPlayer=nbPlayer;
203
204 // We remove uncontrolled stuff from map
205 gui.game.clearingUncontrolledTeams();
206
207 // set the correct alliance
208 gui.game.setAIAlliance();
209
210 // We do some cosmetic fix
211 finalAdjustements();
212
213 // we create the net game
214 net=new NetGame(NULL, gui.game.session.numberOfPlayer, gui.game.players);
215
216 return EE_NO_ERROR;
217 }
218
219 int Engine::initCustom(const std::string &gameName)
220 {
221 if (!loadGame(gameName))
222 return EE_CANT_LOAD_MAP;
223
224 // If the game is a network saved game, we need to toogle net players to ai players:
225 for (int p=0; p<gui.game.session.numberOfPlayer; p++)
226 {
227 printf("Engine::initCustom::player[%d].type=%d.\n", p, gui.game.players[p]->type);
228 if (gui.game.players[p]->type==BasePlayer::P_IP)
229 {
230 gui.game.players[p]->makeItAI(AI::toggleAI);
231 printf("Engine::initCustom::net player (id %d) was made ai.\n", p);
232 }
233 }
234
235 // We do some cosmetic fix
236 gui.adjustLocalTeam();
237 if (!globalContainer->runNoX)
238 {
239 gui.game.renderMiniMap(gui.localTeamNo);
240 gui.adjustInitialViewport();
241 }
242
243 // set the correct alliance
244 gui.game.setAIAlliance();
245
246 // we create the net game
247 net=new NetGame(NULL, gui.game.session.numberOfPlayer, gui.game.players);
248
249 return EE_NO_ERROR;
250 }
251
252 int Engine::initLoadGame()
253 {
254 ChooseMapScreen loadGameScreen("games", "game", true);;
255 int lgs = loadGameScreen.execute(globalContainer->gfx, 40);
256 if (lgs == ChooseMapScreen::CANCEL)
257 return EE_CANCEL;
258
259 return initCustom(loadGameScreen.sessionInfo.getFileName());
260 }
261
262 void Engine::startMultiplayer(MultiplayersJoin *multiplayersJoin)
263 {
264 int p=multiplayersJoin->myPlayerNumber;
265
266 multiplayersJoin->destroyNet=false;
267 for (int j=0; j<multiplayersJoin->sessionInfo.numberOfPlayer; j++)
268 multiplayersJoin->sessionInfo.players[j].destroyNet=false;
269
270 multiplayersJoin->sessionInfo.setLocal(p);
271
272 gui.loadBase(&multiplayersJoin->sessionInfo);
273
274 gui.localPlayer=p;
275 gui.localTeamNo=multiplayersJoin->sessionInfo.players[p].teamNumber;
276 assert(gui.localTeamNo<multiplayersJoin->sessionInfo.numberOfTeam);
277 gui.localTeamNo=gui.localTeamNo % multiplayersJoin->sessionInfo.numberOfTeam; // Ugly relase case.
278
279 // We remove uncontrolled stuff from map
280 gui.game.clearingUncontrolledTeams();
281
282 // set the correct alliance
283 gui.game.setAIAlliance();
284
285 // We do some cosmetic fix
286 finalAdjustements();
287
288 // we create the net game
289 net=new NetGame(multiplayersJoin->socket, gui.game.session.numberOfPlayer, gui.game.players);
290
291 printf("Engine::localPlayer=%d, localTeamNb=%d\n", gui.localPlayer, gui.localTeamNo);
292 }
293
294
295 int Engine::initMutiplayerHost(bool shareOnYOG)
296 {
297 MultiplayersChooseMapScreen multiplayersChooseMapScreen(shareOnYOG);
298
299 int mpcms=multiplayersChooseMapScreen.execute(globalContainer->gfx, 40);
300
301 if (mpcms==MultiplayersChooseMapScreen::CANCEL)
302 return EE_CANCEL;
303 if (mpcms==-1)
304 return -1;
305
306 printf("Engine::the game is sharing ...\n");
307
308 MultiplayersHostScreen multiplayersHostScreen(&(multiplayersChooseMapScreen.sessionInfo), shareOnYOG);
309 int rc=multiplayersHostScreen.execute(globalContainer->gfx, 40);
310 if (rc==MultiplayersHostScreen::STARTED)
311 {
312 if (multiplayersHostScreen.multiplayersJoin==NULL)
313 return EE_CANCEL;
314 else
315 {
316 if (multiplayersHostScreen.multiplayersJoin->myPlayerNumber!=-1)
317 startMultiplayer(multiplayersHostScreen.multiplayersJoin);
318 else
319 return EE_CANCEL;
320 }
321 return EE_NO_ERROR;
322 }
323 else if (rc==-1)
324 return -1;
325
326 printf("Engine::initMutiplayerHost() rc=%d\n", rc);
327
328 return EE_CANCEL;
329 }
330
331 int Engine::initMutiplayerJoin(void)
332 {
333 MultiplayersJoinScreen multiplayersJoinScreen;
334
335 int rc=multiplayersJoinScreen.execute(globalContainer->gfx, 40);
336 if (rc==MultiplayersJoinScreen::STARTED)
337 {
338 startMultiplayer(multiplayersJoinScreen.multiplayersJoin);
339
340 return EE_NO_ERROR;
341 }
342 else if (rc==-1)
343 return -1;
344
345 return EE_CANCEL;
346 }
347
348 int Engine::run(void)
349 {
350 bool doRunOnceAgain=true;
351
352 // Stop menu music, load game music
353 if (globalContainer->runNoX)
354 assert(globalContainer->mix==NULL);
355 else
356 {
357 globalContainer->mix->setNextTrack(2, true);
358 }
359
360 while (doRunOnceAgain)
361 {
362 Uint32 startTick, endTick;
363 bool networkReadyToExecute=true;
364 Sint32 ticksSpentInComputation=40;
365 Sint32 computationAvailableTicks=0;
366 Sint32 ticksToDelayInside=0;
367 Sint32 missedTicksToWait=0;
368
369 startTick=SDL_GetTicks();
370 while (gui.isRunning)
371 {
372 // We always allow the user to use the gui:
373 if (globalContainer->runNoX)
374 {
375 if (!gui.getLocalTeam()->isAlive)
376 {
377 printf("nox::gui.localTeam is dead\n");
378 gui.isRunning=false;
379 }
380 else if (gui.getLocalTeam()->hasWon)
381 {
382 printf("nox::gui.localTeam has won\n");
383 gui.isRunning=false;
384 }
385 else if (gui.game.totalPrestigeReached)
386 {
387 printf("nox::gui.game.totalPrestigeReached\n");
388 gui.isRunning=false;
389 }
390 }
391 else
392 gui.step();
393
394 Sint32 ticksDelayedInside=0;
395 if (!gui.hardPause)
396 {
397 // But some jobs have to be executed synchronously:
398 if (networkReadyToExecute)
399 {
400 gui.syncStep();
401
402 // We get and push local orders
403 net->pushOrder(gui.getOrder(), gui.localPlayer);
404
405 // We store full recursive checkSums data:
406 gui.game.checkSum(net->getCheckSumsListsStorage(), net->getCheckSumsListsStorageForBuildings(), net->getCheckSumsListsStorageForUnits());
407
408 // we get and push ai orders
409 for (int i=0; i<gui.game.session.numberOfPlayer; i++)
410 if (gui.game.players[i]->ai)
411 net->pushOrder(gui.game.players[i]->ai->getOrder(gui.gamePaused), i);
412
413 ticksToDelayInside=net->ticksToDelayInside();
414 ticksDelayedInside=ticksToDelayInside+computationAvailableTicks/2;
415 ticksDelayedInside=(ticksDelayedInside/10)*10; //SDL_Delay() is only 10[ms] acurate
416 if (ticksDelayedInside>0)
417 SDL_Delay(ticksDelayedInside);//Here we may need to wait a bit more, to wait other computers which are slower.
418 else
419 ticksDelayedInside=0;
420 }
421 else
422 ticksDelayedInside=0;
423
424 // We clear the last events
425 gui.game.clearEventsStep();
426
427 // We proceed network:
428 networkReadyToExecute=net->stepReadyToExecute();
429
430 // We get all currents orders from the network and execute them:
431 for (int i=0; i<gui.game.session.numberOfPlayer; i++)
432 {
433 Order *order=net->getOrder(i);
434 gui.executeOrder(order);
435 if (order->needToBeFreedByEngine)
436 delete order;
437 }
438 net->stepExecuted();
439
440 // here we do the real work
441 if (networkReadyToExecute && !gui.gamePaused && !gui.hardPause)
442 gui.game.syncStep(gui.localTeamNo);
443 }
444
445 if (!globalContainer->runNoX)
446 {
447 // we draw
448 gui.drawAll(gui.localTeamNo);
449 globalContainer->gfx->nextFrame();
450
451 // we compute timing
452 endTick=SDL_GetTicks();
453 Sint32 spentTicks=endTick-startTick;
454 ticksSpentInComputation=spentTicks-ticksDelayedInside;
455 computationAvailableTicks=40-ticksSpentInComputation;
456 Sint32 ticksToWait=computationAvailableTicks+ticksToDelayInside+missedTicksToWait;
457 if (ticksToWait>0)
458 {
459 missedTicksToWait=ticksToWait%10;
460 ticksToWait=ticksToWait-missedTicksToWait; //SDL_Delay() is only 10[ms] acurate
461 if (ticksToWait>0)
462 SDL_Delay(ticksToWait);
463 }
464 else
465 missedTicksToWait=0;
466 startTick=SDL_GetTicks();
467
468 // we set CPU stats
469 net->setLeftTicks(computationAvailableTicks);//We may have to tell others IP players to wait for our slow computer.
470 gui.setCpuLoad(ticksSpentInComputation);
471 if (networkReadyToExecute && !gui.gamePaused)
472 {
473 Sint32 i=computationAvailableTicks;
474 if (i<0)
475 i=0;
476 else if (i>=40)
477 i=40;
478 cpuStats[i]++;
479 }
480 }
481 }
482
483 delete net;
484 net=NULL;
485
486 if (gui.exitGlobCompletely)
487 return -1; // There is no bypass for the "close window button"
488
489 doRunOnceAgain=false;
490
491 if (gui.toLoadGameFileName[0])
492 {
493 int rv=initCustom(gui.toLoadGameFileName);
494 if (rv==EE_NO_ERROR)
495 doRunOnceAgain=true;
496 gui.toLoadGameFileName[0]=0; // Avoid the communication system between GameGUI and Engine to loop.
497 }
498 else if (gui.game.nextMap.length() > 0)
499 {
500 // if we have won, managed to load next map, we do it again. Only campaigns can be linked, so we look into the campaigns subdirectory
501 if (gui.game.isGameEnded && gui.getLocalTeam()->isAlive)
502 {
503 std::string filename = std::string("campaigns/") + gui.game.nextMap;
504 doRunOnceAgain = (initCampaign(filename.c_str()) == EE_NO_ERROR);
505 }
506 }
507 }
508
509 if (globalContainer->runNoX)
510 return -1;
511 else
512 {
513 // Restart menu music
514 assert(globalContainer->mix);
515 globalContainer->mix->setNextTrack(1);
516
517 // Display End Game Screen
518 EndGameScreen endGameScreen(&gui);
519 int result = endGameScreen.execute(globalContainer->gfx, 40);
520
521 // Return
522 return (result == -1) ? -1 : EE_NO_ERROR;
523 }
524 }
525
526 bool Engine::loadGame(const std::string &filename)
527 {
528 InputStream *stream = new BinaryInputStream(Toolkit::getFileManager()->openInputStreamBackend(filename));
529 if (stream->isEndOfStream())
530 {
531 std::cerr << "Engine::loadGame(\"" << filename << "\") : error, can't open file." << std::endl;
532 delete stream;
533 return false;
534 }
535 else
536 {
537 bool res = gui.load(stream);
538 delete stream;
539 if (!res)
540 {
541 std::cerr << "Engine::loadGame(\"" << filename << "\") : error, can't load game." << std::endl;
542 return false;
543 }
544 }
545
546 std::cout << "Engine::loadGame(\"" << filename << "\") : game successfully loaded." << std::endl;
547 return true;
548 }
549
550 void Engine::finalAdjustements(void)
551 {
552 gui.adjustLocalTeam();
553 if (!globalContainer->runNoX)
554 {
555 gui.game.renderMiniMap(gui.localTeamNo);
556 gui.adjustInitialViewport();
557 }
558 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26