1 /***************************************************************************
2 session.cpp - Game session manager
3 -------------------
4 begin : Sat May 3 2003
5 copyright : (C) 2003 by Gabor Torok
6 email : cctorok@yahoo.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "common/constants.h"
18 #include "session.h"
19 #include "render/renderlib.h"
20 #include "rpg/rpglib.h"
21 #include "item.h"
22 #include "creature.h"
23 #include "sqbinding/sqbinding.h"
24 #include "test/combattest.h"
25 #include "shapepalette.h"
26 #include "render/cutscene.h"
27 #include <iostream>
28 #include <stdlib.h>
29 //#include <strings.h>
30
31 #include "creature.h"
32 #include "persist.h"
33 #include "io/file.h"
34 #include "configlang.h"
35 #include "sound.h"
36
37 // ###### MS Visual C++ specific ######
38 #if defined(_MSC_VER) && defined(_DEBUG)
39 # define new DEBUG_NEW
40 # undef THIS_FILE
41 static char THIS_FILE[] = __FILE__;
42 #endif
43
44 using namespace std;
45
46 Session *Session::instance = NULL;
47
48 /**
49 *@author Gabor Torok
50 */
Session(GameAdapter * adapter)51 Session::Session( GameAdapter *adapter )
52 : chapterImage()
53 , characters( NULL ) {
54 this->exiting = false;
55 this->adapter = adapter;
56 sound = NULL;
57 shapePal = NULL;
58 party = NULL;
59 map = NULL;
60 board = NULL;
61 cutscene = NULL;
62 #ifdef HAVE_SDL_NET
63 server = NULL;
64 client = NULL;
65 #endif
66 multiplayerGame = false;
67 currentMission = NULL;
68 chapterImageWidth = chapterImageHeight = 0;
69 showChapterIntro = false;
70 squirrel = NULL;
71 savegame = "";
72 loadgame = "";
73 strcpy( scoreid, "" );
74 dataInitialized = NOT_INITIALIZED;
75 Session::instance = this;
76 autosave = false;
77 terrainGenerator = NULL;
78 strcpy( interruptFunction, "" );
79 }
80
~Session()81 Session::~Session() {
82 if( !isExiting() ) {
83 SpecialSkill::unInitSkills();
84 Monster::unInitMonsters();
85 delete characters;
86 MagicSchool::unInitMagic();
87 Rpg::unInitRpg();
88 if ( squirrel ) delete squirrel;
89 deleteCreaturesAndItems();
90 delete party;
91 party = NULL; // adapter destruction may need it
92 delete sound;
93 if ( board ) delete board;
94 if ( cutscene ) delete cutscene;
95 #ifdef HAVE_SDL_NET
96 delete server;
97 delete client;
98 #endif
99 if ( map ) delete map;
100 delete shapePal;
101 shapePal = NULL; // adapter destruction may need it
102 delete adapter;
103 }
104 }
105
initialize()106 void Session::initialize() {
107 sound = new Sound( adapter->getPreferences() );
108 shapePal = new ShapePalette( this );
109 cutscene = new Cutscene( this );
110 adapter->setSession( this );
111 adapter->initVideo();
112 shapePal->preInitialize();
113 // init the fonts and ui
114 //adapter->initStart(12, "Loading shapes...");
115 }
116
start()117 void Session::start() {
118 adapter->start();
119 }
120
doInitData()121 void Session::doInitData() {
122 adapter->setUpdate( _( "Loading Shapes" ) );
123 shapePal->initialize();
124
125 // read the skills, etc.
126 adapter->setUpdate( _( "Loading Professions" ) );
127 Rpg::initRpg();
128
129 // initialize the items
130 adapter->setUpdate( _( "Loading Items" ) );
131 RpgItem::initItems( shapePal );
132
133 // initialize magic
134 adapter->setUpdate( _( "Loading Spells" ) );
135 MagicSchool::initMagic();
136
137 // init professions
138 adapter->setUpdate( _( "Loading Characters" ) );
139 characters = new Characters;
140
141 // initialize the monsters (they use items, magic)
142 adapter->setUpdate( _( "Loading Creatures" ) );
143 Monster::initMonsters();
144
145 adapter->setUpdate( _( "Loading Portraits" ) );
146 shapePal->loadNpcPortraits();
147
148
149 // create the mission board
150 adapter->setUpdate( _( "Loading Missions" ) );
151 board = new Board( this );
152
153
154 // do this before the backpack and optionsdialog (so Z is less than of those)
155 adapter->setUpdate( _( "Initializing Party" ) );
156 party = new Party( this );
157
158 adapter->setUpdate( _( "Initializing Scripting" ) );
159 squirrel = new SqBinding( this );
160
161 adapter->setUpdate( _( "Loading Skills" ) );
162 SpecialSkill::initSkills();
163
164 adapter->setUpdate( _( "Creating Map" ) );
165 map = new Map( adapter, adapter->getPreferences(), getShapePalette() );
166
167 adapter->setUpdate( _( "Initializing UI" ) );
168 adapter->initUI();
169
170 adapter->setUpdate( "" );
171 }
172
initData()173 void Session::initData() {
174 if ( dataInitialized == NOT_INITIALIZED ) {
175 dataInitialized = INIT_STARTED;
176 doInitData();
177 dataInitialized = INIT_DONE;
178 }
179 }
180
quit(int value)181 void Session::quit( int value ) {
182 // FIXME: if(getSDLHandler()) getSDLHandler()->quit(value);
183 exit( value );
184 }
185
186 #ifdef HAVE_SDL_NET
runServer(int port)187 void Session::runServer( int port ) {
188 GameStateHandler *gsh = new TestGameStateHandler();
189 server = new Server( port ? port : DEFAULT_SERVER_PORT );
190 server->setGameStateHandler( gsh );
191
192 // wait for the server to quit
193 int status;
194 SDL_WaitThread( server->getThread(), &status );
195
196 delete gsh;
197 }
198
runClient(char const * host,int port,char const * userName)199 void Session::runClient( char const* host, int port, char const* userName ) {
200 CommandInterpreter *ci = new TestCommandInterpreter();
201 GameStateHandler *gsh = new TestGameStateHandler();
202 client = new Client( host, port, userName, ci );
203 client->setGameStateHandler( gsh );
204 if ( !client->login() ) {
205 cerr << Constants::getMessage( Constants::CLIENT_CANT_CONNECT_ERROR ) << endl;
206 return;
207 }
208
209 // connect as a character
210 // Party *party = new Party(this);
211 Creature *pc[MAX_PARTY_SIZE];
212 int pcCount;
213 Party::createHardCodedParty( this, pc, &pcCount );
214 cerr << "Sending character: " << pc[0]->getName() << endl;
215 getParty()->resetMultiplayer( pc[0] );
216
217 char message[80];
218 while ( true ) {
219 cout << "> ";
220 int c;
221 int n = 0;
222 while ( n < 79 && ( c = getchar() ) != '\n' ) message[n++] = c;
223 message[n] = 0;
224 client->sendChatTCP( message );
225 //client->sendRawTCP(message);
226 }
227
228 delete ci;
229 delete gsh;
230 }
231
startServer(GameStateHandler * gsh,int port)232 void Session::startServer( GameStateHandler *gsh, int port ) {
233 server = new Server( port );
234 server->setGameStateHandler( gsh );
235 multiplayerGame = true;
236 }
237
startClient(GameStateHandler * gsh,CommandInterpreter * ci,char const * host,int port,char const * username)238 void Session::startClient( GameStateHandler *gsh, CommandInterpreter *ci, char const* host, int port, char const* username ) {
239 client = new Client( host, port, username, ci );
240 client->setGameStateHandler( gsh );
241 multiplayerGame = true;
242 }
243
stopClientServer()244 void Session::stopClientServer() {
245 if ( server ) {
246 delete server;
247 server = NULL;
248 }
249 if ( client ) {
250 delete client;
251 client = NULL;
252 }
253 multiplayerGame = false;
254 }
255
256 #endif
257
newItem(RpgItem * rpgItem,int level,Spell * spell,bool loading)258 Item *Session::newItem( RpgItem *rpgItem, int level, Spell *spell, bool loading ) {
259 // don't randomize special items
260 if ( rpgItem->isSpecial() ) loading = true;
261 int itemLevel = level;
262 if ( !loading ) {
263 itemLevel += Util::dice( 6 ) - 3;
264 }
265 if ( itemLevel < 1 ) itemLevel = 1;
266 Item *item = new Item( this, rpgItem, itemLevel );
267 if ( spell ) item->setSpell( spell );
268 newItems.push_back( item );
269 if ( rpgItem->isSpecial() ) setSpecialItem( rpgItem, item );
270 return item;
271 }
272
addItemFromScript(char * name,int x,int y,int z,bool isContainer,int level,int depth)273 Item *Session::addItemFromScript( char *name, int x, int y, int z, bool isContainer, int level, int depth ) {
274 RpgItem *rpgItem = RpgItem::getItemByName( name );
275 if ( !rpgItem ) {
276 cerr << "*** Error: no item named " << name << endl;
277 return NULL;
278 }
279 Item *item = newItem( rpgItem );
280 // register with squirrel
281 getSquirrel()->registerItem( item );
282
283 if ( isContainer ) {
284 getGameAdapter()->fillContainer( item, level, depth );
285 }
286
287 getMap()->setItem( x, y, z, item );
288
289 return item;
290 }
291
addCreatureFromScript(char * creatureType,int cx,int cy,int * fx,int * fy)292 Creature *Session::addCreatureFromScript( char *creatureType, int cx, int cy, int *fx, int *fy ) {
293 Monster *monster = Monster::getMonsterByName( creatureType );
294 if ( !monster ) {
295 cerr << "*** Error: no monster named " << creatureType << endl;
296 return NULL;
297 }
298 GLShape *shape = getShapePalette()->
299 getCreatureShape( monster->getModelName(),
300 monster->getSkinName(),
301 monster->getScale(),
302 monster );
303 Creature *replacement = newCreature( monster, shape );
304
305 // register with squirrel
306 getSquirrel()->registerCreature( replacement );
307 for ( int i = 0; i < replacement->getBackpackContentsCount(); i++ ) {
308 getSquirrel()->registerItem( replacement->getBackpackItem( i ) );
309 }
310
311 if ( fx && fy ) {
312 replacement->findPlace( cx, cy, fx, fy );
313 } else {
314 //int ffx, ffy;
315 //replacement->findPlace( cx, cy, &ffx, &ffy );
316 replacement->moveTo( cx, cy, 0 );
317 getMap()->setCreature( cx, cy, 0, replacement );
318 }
319 replacement->cancelTarget();
320
321 return replacement;
322 }
323
replaceCreature(Creature * creature,char * newCreatureType)324 Creature *Session::replaceCreature( Creature *creature, char *newCreatureType ) {
325 int cx = toint( creature->getX() );
326 int cy = toint( creature->getY() );
327 int cz = toint( creature->getZ() );
328 getMap()->removeCreature( cx, cy, cz );
329 creature->moveTo( -1, -1, 0 ); // remove its marker
330 creature->setStateMod( StateMod::dead, true ); // make sure it doesn't move
331
332 int fx, fy;
333 Creature *replacement = addCreatureFromScript( newCreatureType, cx, cy, &fx, &fy );
334 if ( replacement ) {
335 getMap()->startEffect( fx, fy, 1,
336 Constants::EFFECT_DUST,
337 ( Constants::DAMAGE_DURATION * 4 ),
338 replacement->getShape()->getWidth(),
339 replacement->getShape()->getDepth() );
340 char msg[120];
341 snprintf( msg, 120, _( "%s transforms into another shape in front of your very eyes!" ),
342 creature->getName() );
343 getGameAdapter()->writeLogMessage( msg );
344
345 cerr << "is npc? " << replacement->isNpc() << endl;
346 }
347 return replacement;
348 }
349
setVisible(Creature * creature,bool b)350 void Session::setVisible( Creature *creature, bool b ) {
351 if ( b && !isVisible( creature ) ) {
352 nonVisibleCreatures.erase( creature );
353 getMap()->setCreature( toint( creature->getX() ), toint( creature->getY() ), toint( creature->getZ() ), creature );
354 } else if ( !b && isVisible( creature ) ) {
355 nonVisibleCreatures.insert( creature );
356 getMap()->removeCreature( toint( creature->getX() ), toint( creature->getY() ), toint( creature->getZ() ) );
357 }
358 }
359
isVisible(Creature * creature)360 bool Session::isVisible( Creature *creature ) {
361 return( nonVisibleCreatures.find( creature ) == nonVisibleCreatures.end() );
362 }
363
364 // creatures created for the mission
newCreature(Monster * monster,GLShape * shape,bool loaded)365 Creature *Session::newCreature( Monster *monster, GLShape *shape, bool loaded ) {
366 Creature *c = new Creature( this, monster, shape, !loaded );
367 creatures.push_back( c );
368 return c;
369 }
370
newCreature(Character * character,char const * name,int sex,int model)371 Creature *Session::newCreature( Character *character, char const* name, int sex, int model ) {
372 Creature *c = new Creature( this, character, name, sex, model );
373 creatures.push_back( c );
374 return c;
375 }
376
removeCreatureRef(Creature * creature,int index)377 bool Session::removeCreatureRef( Creature *creature, int index ) {
378 for ( vector<Creature*>::iterator i = creatures.begin(); i != creatures.end(); ++i ) {
379 Creature *c = *i;
380 if ( c == creature ) {
381 creatures.erase( i );
382 return true;
383 }
384 }
385 return false;
386 }
387
addCreatureRef(Creature * creature,int index)388 void Session::addCreatureRef( Creature *creature, int index ) {
389 creatures.push_back( creature );
390 }
391
deleteCreaturesAndItems(bool missionItemsOnly)392 void Session::deleteCreaturesAndItems( bool missionItemsOnly ) {
393 // delete the items and creatures created for this mission
394 // (except items in backpack)
395 if ( !missionItemsOnly ) {
396 for ( int i = 0; i < static_cast<int>( newItems.size() ); i++ ) {
397 if ( newItems[i]->isSpecial() ) {
398 // put special item back into play
399 special.erase( newItems[i]->getRpgItem() );
400 }
401 delete newItems[i];
402 }
403 newItems.clear();
404 } else {
405 for ( int i = 0; i < static_cast<int>( newItems.size() ); i++ ) {
406 bool inBackpack = false;
407 for ( int t = 0; t < getParty()->getPartySize(); t++ ) {
408 if ( getParty()->getParty( t )->isItemInBackpack( newItems[i] ) ) {
409 inBackpack = true;
410 break;
411 }
412 }
413 if ( !inBackpack ) {
414 if ( newItems[i]->isSpecial() ) {
415 // put special item back into play
416 special.erase( newItems[i]->getRpgItem() );
417 }
418 delete newItems[i];
419 for ( int t = i + 1; t < static_cast<int>( newItems.size() ); t++ ) {
420 newItems[t - 1] = newItems[t];
421 }
422 newItems.pop_back();
423 i--;
424 }
425 }
426 }
427 for ( int i = 0; i < static_cast<int>( creatures.size() ); i++ ) {
428 delete creatures[i];
429 }
430 creatures.clear();
431 nonVisibleCreatures.clear();
432
433 /*
434 cerr << "***************************************" << endl;
435 cerr << "After mission: " <<
436 " creatureCount=" << creatureCount <<
437 " itemCount=" << itemCount << endl;
438 cerr << "***************************************" << endl;
439 */
440 getShapePalette()->debugLoadedModels();
441 }
442
removeCreature(Creature * creature)443 bool Session::removeCreature( Creature *creature ) {
444 getMap()->removeCreature( toint( creature->getX() ), toint( creature->getY() ), toint( creature->getZ() ) );
445 creature->moveTo( -1, -1, 0 ); // remove its marker
446 creature->setStateMod( StateMod::dead, true ); // make sure it doesn't move
447 return removeCreatureRef( creature, 0 );
448 }
449
450
451 /// Return the closest (visible) monster within the given radius or null if none can be found.
452
getClosestMonster(int x,int y,int w,int h,int radius)453 Creature *Session::getClosestMonster( int x, int y, int w, int h, int radius ) {
454 float dist;
455 float minDist = 0;
456 Creature *p = NULL;
457 for ( int i = 0; i < getCreatureCount(); i++ ) {
458 if ( !getCreature( i )->getStateMod( StateMod::dead ) && !getCreature( i )->getStateMod( StateMod::possessed ) && getCreature( i )->isMonster() && map->isLocationVisible( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ) ) && map->isLocationInLight( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ), getCreature( i )->getShape() ) ) {
459 dist = Constants::distance( x, y, w, h, getCreature( i )->getX(), getCreature( i )->getY(), getCreature( i )->getShape()->getWidth(), getCreature( i )->getShape()->getDepth() );
460 if ( dist <= static_cast<float>( radius ) && ( !p || dist < minDist ) ) {
461 p = getCreature( i );
462 minDist = dist;
463 }
464 }
465 }
466 return p;
467 }
468
469 /// Return the closest (visible) non-monster creature within the given radius or null if none can be found.
470
getClosestGoodGuy(int x,int y,int w,int h,int radius)471 Creature *Session::getClosestGoodGuy( int x, int y, int w, int h, int radius ) {
472 float dist;
473 float minDist = 0;
474 Creature *p = NULL;
475
476 // Search for the nearest non-monster, non-harmless creature.
477 for ( int i = 0; i < getCreatureCount(); i++ ) {
478 if ( !getCreature( i )->getStateMod( StateMod::dead ) && !getCreature( i )->getStateMod( StateMod::possessed ) && map->isLocationInLight( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ), getCreature( i )->getShape() ) && !( getCreature( i )->isMonster() || getCreature( i )->isHarmlessAnimal() ) ) {
479 dist = Constants::distance( x, y, w, h, getCreature( i )->getX(), getCreature( i )->getY(), getCreature( i )->getShape()->getWidth(), getCreature( i )->getShape()->getDepth() );
480 if ( dist <= static_cast<float>( radius ) && ( !p || dist < minDist ) ) {
481 p = getCreature( i );
482 minDist = dist;
483 }
484 }
485 }
486
487 // Check whether any party members are nearer.
488 for ( int i = 0; i < getParty()->getPartySize(); i++ ) {
489 if ( !getParty()->getParty(i)->getStateMod( StateMod::dead ) && !getParty()->getParty(i)->getStateMod( StateMod::possessed ) ) {
490 dist = Constants::distance( x, y, w, h, getParty()->getParty(i)->getX(), getParty()->getParty(i)->getY(), getParty()->getParty(i)->getShape()->getWidth(), getParty()->getParty(i)->getShape()->getDepth() );
491 if ( dist <= static_cast<float>( radius ) && ( !p || dist < minDist ) ) {
492 p = getParty()->getParty(i);
493 minDist = dist;
494 }
495 }
496 }
497
498 return p;
499 }
500
501 /// Return a random (visible) monster within the given radius or null if none can be found.
502
getRandomNearbyMonster(int x,int y,int w,int h,int radius)503 Creature *Session::getRandomNearbyMonster( int x, int y, int w, int h, int radius ) {
504 vector<Creature*> possibleTargets;
505 Creature *p = NULL;
506
507 for ( int i = 0; i < getCreatureCount(); i++ ) {
508 if ( !getCreature( i )->getStateMod( StateMod::dead ) && !getCreature( i )->getStateMod( StateMod::possessed ) && map->isLocationVisible( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ) ) && map->isLocationInLight( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ), getCreature( i )->getShape() ) && getCreature( i )->isMonster() ) {
509 if ( Constants::distance( x, y, w, h, getCreature( i )->getX(), getCreature( i )->getY(), getCreature( i )->getShape()->getWidth(), getCreature( i )->getShape()->getDepth() ) <= (float)radius ) {
510 possibleTargets.push_back ( getCreature( i ) );
511 }
512 }
513 }
514
515 if ( !possibleTargets.empty() ) p = possibleTargets [ Util::pickOne( 0, possibleTargets.size() - 1 ) ];
516 return p;
517 }
518
519 /// Return a random (visible) non-monster within the given radius or null if none can be found.
520
getRandomNearbyGoodGuy(int x,int y,int w,int h,int radius)521 Creature *Session::getRandomNearbyGoodGuy( int x, int y, int w, int h, int radius ) {
522 vector<Creature*> possibleTargets;
523 Creature *p = NULL;
524
525 for ( int i = 0; i < getCreatureCount(); i++ ) {
526 if ( !getCreature( i )->getStateMod( StateMod::dead ) && !getCreature( i )->getStateMod( StateMod::possessed ) && map->isLocationVisible( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ) ) && map->isLocationInLight( toint( getCreature( i )->getX() ), toint( getCreature( i )->getY() ), getCreature( i )->getShape() ) && !( getCreature( i )->isMonster() || getCreature( i )->isHarmlessAnimal() ) ) {
527 if ( Constants::distance( x, y, w, h, getCreature( i )->getX(), getCreature( i )->getY(), getCreature( i )->getShape()->getWidth(), getCreature( i )->getShape()->getDepth() ) <= (float)radius ) {
528 possibleTargets.push_back ( getCreature( i ) );
529 }
530 }
531 }
532
533 for ( int i = 0; i < getParty()->getPartySize(); i++ ) {
534 if ( !getParty()->getParty(i)->getStateMod( StateMod::dead ) && !getParty()->getParty(i)->getStateMod( StateMod::possessed ) ) {
535 if ( Constants::distance( x, y, w, h, getParty()->getParty(i)->getX(), getParty()->getParty(i)->getY(), getParty()->getParty(i)->getShape()->getWidth(), getParty()->getParty(i)->getShape()->getDepth() ) <= (float)radius ) {
536 possibleTargets.push_back ( getParty()->getParty( i ) );
537 }
538 }
539 }
540
541 if ( !possibleTargets.empty() ) p = possibleTargets [ Util::pickOne( 0, possibleTargets.size() - 1 ) ];
542 return p;
543 }
544
creatureDeath(Creature * creature)545 void Session::creatureDeath( Creature *creature ) {
546 bool result;
547 squirrel->callBoolMethod( "creatureDeath",
548 squirrel->getCreatureRef( creature ),
549 &result );
550 // FIXME: not used currently
551 //if( !result ) return;
552
553 // dismiss summoned creatures
554 creature->dismissSummonedCreatures();
555
556 if ( creature == party->getPlayer() ) {
557 party->switchToNextLivePartyMember();
558 }
559 // remove from the map; the object will be cleaned up at the end of the mission
560 map->removeCreature( toint( creature->getX() ),
561 toint( creature->getY() ),
562 toint( creature->getZ() ) );
563 // add a container object instead
564 //if(battleRound.size() > 0) creature->getShape()->setCurrentAnimation(MD2_DEATH1);
565 Item *item = newItem( RpgItem::getItemByName( "Corpse" ) );
566 // add creature's backpack to container
567 map->setItem( toint( creature->getX() ),
568 toint( creature->getY() ),
569 toint( creature->getZ() ), item );
570 int n = creature->getBackpackContentsCount();
571 for ( int i = 0; i < n; i++ ) {
572 // make it contain all items, no matter what size
573 item->addContainedItem( creature->removeFromBackpack( 0 ), true );
574 }
575 creature->setStateMod( StateMod::dead, true );
576
577 creature->setCauseOfDeath( creature->getPendingCauseOfDeath() );
578
579 // cancel target, otherwise segfaults on resurrection
580 creature->cancelTarget();
581
582 if ( creature->isPartyMember() ) {
583 char message[255];
584 snprintf( message, 255, _( " %s dies!" ), creature->getName() );
585 getGameAdapter()->startTextEffect( message );
586 }
587
588 #ifdef HAVE_SDL_NET
589 bool foundLivePlayer = false;
590 for ( int i = 0; i < getParty()->getPartySize(); i++ ) {
591 if ( !getParty()->getParty( i )->getStateMod( StateMod::dead ) ) {
592 foundLivePlayer = true;
593 break;
594 }
595 }
596 if ( !foundLivePlayer ) {
597 /*
598 Hack: only info about the lead player is uploaded. Set the cause of death on that
599 player now. This is a hack so cod need not be persisted in savegame.
600 */
601 getParty()->getParty( 0 )->setCauseOfDeath( creature->getCauseOfDeath() );
602 getGameAdapter()->askToUploadScore();
603 }
604 #endif
605 }
606
607 // define below to enable savegame testing
608 //#define TESTING_SAVEGAME 1
609
testSaveGame(Session * session)610 void testSaveGame( Session *session ) {
611 cerr << "Loading savegame." << endl;
612 Uint32 storylineIndex;
613 Uint32 partySize;
614 Creature *pc[MAX_PARTY_SIZE];
615
616 {
617 FILE *fp = fopen( "/home/gabor/.scourge/savegame.dat", "rb" );
618 File *file = new File( fp );
619 Uint32 n = PERSIST_VERSION;
620 file->read( &n );
621 file->read( &storylineIndex );
622 file->read( &partySize );
623 cerr << "LOADING: " << endl;
624 for ( int i = 0; i < static_cast<int>( partySize ); i++ ) {
625 CreatureInfo *info = Persist::loadCreature( file );
626 pc[i] = Creature::load( session, info );
627 if ( i == 0 ) {
628 for ( int t = 0; t < Skill::SKILL_COUNT; t++ ) {
629 cerr << "\tinfo=" << info->skills[t] <<
630 " infoMOD=" << info->skillMod[t] <<
631 " SK=" << pc[i]->getSkill( t, false ) <<
632 " MOD=" << pc[i]->getSkillMod( t ) <<
633 " BON=" << pc[i]->getSkillBonus( t ) <<
634 endl;
635 }
636 }
637 Persist::deleteCreatureInfo( info );
638 }
639 delete file;
640 }
641
642 cerr << "Saving savegame." << endl;
643 {
644 FILE *fp = fopen( "/home/gabor/.scourge/out.dat", "wb" );
645 if ( !fp ) {
646 cerr << "Error creating savegame file!" << endl;
647 return;
648 }
649 File *file = new File( fp );
650 Uint32 n = PERSIST_VERSION;
651 file->write( &n );
652 file->write( &storylineIndex );
653 file->write( &partySize );
654 for ( int i = 0; i < static_cast<int>( partySize ); i++ ) {
655 CreatureInfo *info = pc[i]->save();
656 Persist::saveCreature( file, info );
657 Persist::deleteCreatureInfo( info );
658 }
659 delete file;
660 }
661
662 cerr << "AFTER SAVING: " << endl;
663 for ( int t = 0; t < Skill::SKILL_COUNT; t++ ) {
664 cerr << "\tSK=" << pc[0]->getSkill( t, false ) << endl;
665 }
666
667 cerr << "Done." << endl;
668 }
669
670 //#define TESTING_CONFIG
671
runGame(GameAdapter * adapter,int argc,char * argv[])672 int Session::runGame( GameAdapter *adapter, int argc, char *argv[] ) {
673
674 int err = Constants::initRootDir( argc, argv );
675 if ( err ) return err;
676
677 #ifdef TESTING_CONFIG
678 ConfigLang *config = ConfigLang::load( "config/scourge.cfg" );
679 config->debug();
680 delete config;
681 exit( 0 );
682 #endif
683
684 #ifdef TESTING_SAVEGAME
685 adapter = new GameAdapter( adapter->getPreferences() );
686 #endif
687 // -=K=-: its sole session ... so i make it static
688 static Session session( adapter );
689 session.initialize();
690 if ( argc >= 2 && !strcmp( argv[1], "--run-tests" ) ) {
691 char const* path = ( argc >= 3 ?
692 argv[2] :
693 "/home/gabor/sourceforge/scourge/api/tests" );
694 if ( CombatTest::executeTests( &session, path ) ) {
695 cout << "Tests were succesfully written to: " << path << endl;
696 return 0;
697 } else {
698 cerr << "Error while running tests." << endl;
699 return 1;
700 }
701 return 0;
702 }
703 #ifndef TESTING_SAVEGAME
704 char* str = new char[100]; strcpy(str,"leak #7 (5 unknown leaks)"); // a test leak
705 session.start();
706 #else
707 testSaveGame( &session );
708 #endif
709
710 return EXIT_SUCCESS;
711 }
712
getCountForDate(char * key,bool withinLastHour)713 int Session::getCountForDate( char *key, bool withinLastHour ) {
714 int count = 0;
715 char const* value = getSquirrel()->getValue( key );
716 if ( value != NULL ) {
717 char s[255];
718 strcpy( s, value );
719 char *p = strtok( s, "+" );
720 if ( p != NULL ) {
721 char *q = strtok( NULL, "+" );
722 Date *lastUsed = new Date( p );
723 Date now = getParty()->getCalendar()->getCurrentDate();
724
725 bool withinDate = ( ( withinLastHour && now.isAnHourLater( *lastUsed ) ) || ( !withinLastHour && now.isADayLater( *lastUsed ) ) );
726
727 // did specified amount of time pass?
728 if ( !withinDate ) {
729 if ( q ) {
730 count = atoi( q );
731 }
732 }
733 delete lastUsed;
734 }
735 }
736 return count;
737 }
738
setCountForDate(char * key,int value)739 void Session::setCountForDate( char *key, int value ) {
740 char s[255];
741 snprintf( s, 255, "%s+%d",
742 getParty()->getCalendar()->getCurrentDate().getShortString(),
743 value );
744 getSquirrel()->setValue( key, s );
745 }
746
setSavegameName(string & s)747 void Session::setSavegameName( string& s ) {
748 savegame = s;
749 }
750
setSavegameTitle(string & s)751 void Session::setSavegameTitle( string& s ) {
752 savetitle = s;
753 }
754
getCreatureByName(char const * name)755 Creature *Session::getCreatureByName( char const* name ) {
756 for ( unsigned int i = 0; i < creatures.size(); i++ ) {
757 if ( !strcmp( creatures[i]->getName(), name ) ) return creatures[i];
758 }
759 return NULL;
760 }
761
setCurrentMission(Mission * mission)762 void Session::setCurrentMission( Mission *mission ) {
763 Mission *oldMission = currentMission;
764 currentMission = mission;
765 getGameAdapter()->refreshBackpackUI();
766 if ( oldMission != currentMission && currentMission && currentMission->isStoryLine() && !currentMission->isReplay() ) {
767 char filename[300];
768 snprintf( filename, 300, "chapter%d.png", currentMission->getChapter() );
769 setChapterImage( filename );
770 }
771
772 // initialize script objects
773 getSquirrel()->initLevelObjects();
774 }
775
setChapterImage(char * image)776 void Session::setChapterImage( char *image ) {
777 char filename[300];
778 snprintf( filename, 300, "/chapters/%s", image );
779 chapterImageTexture.load( filename );
780 if ( !chapterImageTexture.isSpecified() ) {
781 cerr << "Error loading chapter image " << image << endl;
782 chapterImage.clear();
783 // its clear anyway, chapterImageTexture.clear();
784 chapterImageWidth = chapterImageHeight = 0;
785 } else {
786 //chapterImageTexture = shapePal->loadGLTextures(filename, true);
787 GLclampf pri = 0.1f; chapterImageTexture.glPrioritize( pri );
788 chapterImageWidth = 1000;
789 chapterImageHeight = 458;
790 cerr << "***********************************" << endl;
791 cerr << "Loaded chapter art: " << filename <<
792 " dimensions=" << chapterImageWidth << "," << chapterImageHeight << endl;
793 cerr << "***********************************" << endl;
794 }
795 }
796
797 std::string HQ_AMBIENT_SOUND = "hq";
getAmbientSoundName()798 std::string& Session::getAmbientSoundName() {
799 return getCurrentMission() ? getCurrentMission()->getAmbientSoundName() : HQ_AMBIENT_SOUND;
800 }
801
playSound(const std::string & sound,int panning)802 void Session::playSound( const std::string& sound, int panning ) {
803 getSound()->playSound( sound, panning );
804 }
805