1 /***************************************************************************
2 party.cpp - Party class
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
18 #include "common/constants.h"
19 #include "party.h"
20 #include "render/renderlib.h"
21 #include "rpg/rpglib.h"
22 #include "item.h"
23 #include "creature.h"
24 #include "shapepalette.h"
25 #include "sqbinding/sqbinding.h"
26
27 using namespace std;
28
29 Creature *Party::lastPlayer = NULL;
30
31 //#define RANDOM_PARTY 1
32
33 //#define TEST_POSSESSION 1
34
35 #define PARTY_FOLLOW_INTERVAL 1500
36
Party(Session * session)37 Party::Party( Session *session ) {
38 this->session = session;
39
40 startRound = true;
41 calendar = Calendar::getInstance();
42
43 partySize = 0;
44
45 loadedCount = 0;
46 storylineIndex = 0;
47 }
48
~Party()49 Party::~Party() {
50 // its static instance: delete calendar;
51 deleteParty();
52 }
53
deleteParty()54 void Party::deleteParty() {
55 partySet.clear();
56 for ( int i = 0; i < getPartySize(); i++ ) {
57 delete party[i];
58 party[i] = NULL;
59 }
60 partySize = 0;
61 player = NULL;
62 lastPlayer = NULL;
63 }
64
reset()65 void Party::reset() {
66 maxSkills.clear();
67 deleteParty();
68 if ( loadedCount ) {
69 for ( int i = 0; i < loadedCount; i++ ) {
70 party[i] = loadedParty[i];
71 }
72 partySize = loadedCount;
73 loadedCount = 0;
74 session->getBoard()->setStorylineIndex( storylineIndex );
75 storylineIndex = 0;
76 } else {
77 //createHardCodedParty(session, party, &partySize);
78 session->getGameAdapter()->createParty( party, &partySize );
79 }
80 player = party[0];
81 for ( int i = 0; i < partySize; i++ ) {
82 partySet.insert( party[i] );
83 }
84
85 #ifdef TEST_POSSESSION
86 cerr << "****************************" << endl;
87 cerr << "****************************" << endl;
88 cerr << "Warning: possession testing is turned on." << endl;
89 cerr << "****************************" << endl;
90 cerr << "****************************" << endl;
91 if ( partySize > 2 && party[2] ) party[2]->setStateMod( StateMod::possessed, true );
92 if ( partySize > 3 && party[3] ) party[3]->setStateMod( StateMod::possessed, true );
93 #endif
94
95 recomputeMaxSkills();
96 if ( !session->getGameAdapter()->isHeadless() )
97 session->getGameAdapter()->resetPartyUI();
98 }
99
resetMultiplayer(Creature * c)100 void Party::resetMultiplayer( Creature *c ) {
101 maxSkills.clear();
102 deleteParty();
103 party[0] = player = c;
104 party[1] = party[2] = party[3] = NULL;
105 partySize = 1;
106 partySet.insert( c );
107 #ifdef HAVE_SDL_NET
108 // upload your character to the server
109 session->getClient()->sendCharacter( player->save() );
110 #endif
111 session->getParty()->recomputeMaxSkills();
112 if ( !session->getGameAdapter()->isHeadless() )
113 session->getGameAdapter()->resetPartyUI();
114 }
115
116 // set player to be the first non-dead character
setFirstLivePlayer()117 void Party::setFirstLivePlayer() {
118 for ( int i = 0; i < getPartySize(); i++ ) {
119 if ( !party[i]->getStateMod( StateMod::dead ) ) {
120 //setPlayer(getParty(i));
121 setPlayer( i );
122 break;
123 }
124 }
125 }
126
getFirstLivePlayer()127 int Party::getFirstLivePlayer() {
128 for ( int i = 0; i < getPartySize(); i++ ) {
129 if ( !party[i]->getStateMod( StateMod::dead ) ) {
130 return i;
131 }
132 }
133 return -1;
134 }
135
startPartyOnMission()136 void Party::startPartyOnMission() {
137 // Start calendar and add thirst & hunger event scheduling
138 calendar->reset( false );
139
140 player_only = false;
141 partyDead = false;
142
143 setFirstLivePlayer();
144 setFormation( Creature::DIAMOND_FORMATION );
145 getPlayer()->cancelTarget();
146
147 // init the rest of the party
148 for ( int i = 1; i < getPartySize(); i++ ) {
149 //TODO: this is a formation thing. Replace with FormationPathManagers for the party
150 //getParty(i)->setNext(getPlayer(), i);
151 getParty( i )->cancelTarget();
152 getParty( i )->resetSecretDoorAttempts();
153 getParty( i )->resetTrapFindAttempts();
154 }
155 }
156
setPartyMotion(int motion)157 void Party::setPartyMotion( int motion ) {
158 for ( int i = 0; i < getPartySize(); i++ ) {
159 if ( party[i] != player ) party[i]->setMotion( motion );
160 }
161 }
162
163 /// Switches to the next alive party member.
164
165 /// returns false if the switch could not be made,
166 /// because the entire party is dead (the mission failed)
167
switchToNextLivePartyMember()168 bool Party::switchToNextLivePartyMember() {
169 Creature *oldPlayer = player;
170 // find the player's index
171 int n = getPlayerIndex();
172 // switch to next player
173 n++; if ( n >= getPartySize() ) n = 0;
174 for ( int t = 0; t < getPartySize(); t++ ) {
175 if ( !party[n]->getStateMod( StateMod::dead ) ) {
176 setPlayer( n );
177 break;
178 }
179 n++; if ( n >= getPartySize() ) n = 0;
180 }
181 bool res = ( oldPlayer != player );
182 if ( !res ) partyDead = true;
183 return res;
184 }
185
nextPartyMember()186 bool Party::nextPartyMember() {
187 Creature *oldPlayer = player;
188 int n = getPlayerIndex();
189 n++;
190 if ( n >= getPartySize() ) n = 0;
191 setPlayer( n );
192 return( oldPlayer != player );
193 }
194
previousPartyMember()195 bool Party::previousPartyMember() {
196 Creature *oldPlayer = player;
197 int n = getPlayerIndex();
198 n--;
199 if ( n < 0 ) n = getPartySize() - 1;
200 setPlayer( n );
201 return( oldPlayer != player );
202 }
203
getPlayerIndex()204 int Party::getPlayerIndex() {
205 for ( int t = 0; t < getPartySize(); t++ ) {
206 if ( party[ t ] == player ) {
207 return t;
208 }
209 }
210 return -1;
211 }
212
setPlayer(int n,bool updateui)213 void Party::setPlayer( int n, bool updateui ) {
214 if ( n >= getPartySize() ) return;
215 player = party[n];
216 //player->setNextDontMove(NULL, 0);
217 // init the rest of the party
218 // int count = 1;
219 //for(int i = 0; i < getPartySize(); i++) {
220 //if(i != n) party[i]->setNextDontMove(player, count++);
221 // }
222
223 if ( updateui ) {
224 // move = 0;
225 session->getMap()->refresh();
226 session->getMap()->center( toint( player->getX() ), toint( player->getY() ), true );
227 if ( !session->getGameAdapter()->isHeadless() ) {
228 session->getGameAdapter()->refreshBackpackUI( n );
229 session->getGameAdapter()->setPlayerUI( n );
230 }
231
232 // play selection sound
233 if ( lastPlayer != player ) {
234 if ( lastPlayer && !player->getStateMod( StateMod::dead ) ) {
235 //session->playSound(player->getCharacter()->getRandomSound(Constants::SOUND_TYPE_SELECT));
236 int panning = session->getMap()->getPanningFromMapXY( player->getX(), player->getY() );
237 player->playCharacterSound( GameAdapter::SELECT_SOUND, panning );
238 }
239 lastPlayer = player;
240 }
241 }
242 }
243
244
forceStopRound()245 void Party::forceStopRound() {
246 startRound = false;
247 toggleRound();
248 }
249
toggleRound(bool test)250 void Party::toggleRound( bool test ) {
251 if ( startRound == test ) toggleRound();
252 }
253
toggleRound()254 void Party::toggleRound() {
255 startRound = ( startRound ? false : true );
256 if ( startRound ) {
257 session->getGameAdapter()->writeLogMessage( Constants::getMessage( Constants::REAL_TIME_MODE ), Constants::MSGTYPE_SYSTEM );
258 } else {
259 session->getGameAdapter()->writeLogMessage( Constants::getMessage( Constants::TURN_MODE ), Constants::MSGTYPE_SYSTEM );
260 }
261
262 // Freeze / unfreeze calendar
263 calendar->setPause( !startRound );
264
265 // Freeze / unfreeze animations
266 for ( int i = 0; i < getPartySize(); i++ ) {
267 getParty( i )->getShape()->setPauseAnimation( !startRound );
268 }
269 for ( int i = 0; i < session->getCreatureCount(); i++ ) {
270 session->getCreature( i )->getShape()->setPauseAnimation( !startRound );
271 }
272
273 if ( !session->getGameAdapter()->isHeadless() )
274 session->getGameAdapter()->toggleRoundUI( startRound );
275 }
276
277 /**
278 * Sets the target creature for the party.
279 * As far as finding a path toward the target is concerned, this assumes that each party member is
280 * using their preferred weapon. This path will be recomputed during battle anyway if this is not true.
281 **/
setTargetCreature(Creature * creature)282 void Party::setTargetCreature( Creature *creature ) {
283 float range;
284 if ( player_only ) {
285 range = MIN_DISTANCE;
286 if ( player->getPreferredWeapon() > -1 &&
287 player->getEquippedItem( player->getPreferredWeapon() ) ) {
288 range = player->getEquippedItem( player->getPreferredWeapon() )->getRange();
289 }
290 player->setTargetCreature( creature, true, range );
291 } else {
292 for ( int i = 0; i < getPartySize(); i++ ) {
293 range = MIN_DISTANCE;
294 if ( party[i]->getPreferredWeapon() > -1 &&
295 party[i]->getEquippedItem( party[i]->getPreferredWeapon() ) ) {
296 range = party[i]->getEquippedItem( party[i]->getPreferredWeapon() )->getRange();
297 }
298 party[i]->setTargetCreature( creature, true, range );
299 }
300 }
301 }
302
303 /**
304 * Move the party someplace.
305 * If in group mode and the selected player can't move to the desired
306 * location, pick someone else from the group who can make the move.
307 */
setSelXY(Uint16 mapx,Uint16 mapy,bool cancelIfNotPossible)308 bool Party::setSelXY( Uint16 mapx, Uint16 mapy, bool cancelIfNotPossible ) {
309 if ( isPlayerOnly() ) {
310 getPlayer()->cancelTarget();
311 } else {
312 for ( int i = 0; i < getPartySize(); i++ ) {
313 if ( !getParty( i )->getStateMod( StateMod::dead ) ) {
314 getParty( i )->cancelTarget();
315 }
316 }
317 }
318 // Try to move the current player
319 return getPlayer()->setSelXY( mapx, mapy, cancelIfNotPossible );
320 }
321
isPartyInRange()322 bool Party::isPartyInRange() {
323 bool canMove = true;
324 for ( int t = 0; t < getPartySize(); t++ ) {
325 if ( !party[t]->getStateMod( StateMod::dead ) &&
326 party[t] != player ) {
327 if ( party[t]->getDistanceToSel() > player->getDistanceToSel() &&
328 party[t]->getDistance( player ) > 7 ) {
329 canMove = false;
330 break;
331 }
332 }
333 }
334 return canMove;
335 }
336
movePlayers()337 void Party::movePlayers() {
338 if ( player_only ) {
339 // move everyone
340 for ( int i = 0; i < getPartySize(); i++ ) {
341 if ( !party[i]->getStateMod( StateMod::dead ) ) {
342 party[i]->moveToLocator();
343 }
344 }
345 // center on player
346 session->getMap()->center( toint( player->getX() ), toint( player->getY() ) );
347 } else { // In group mode:
348
349 // move the leader
350 if ( !player->getStateMod( StateMod::dead ) ) {
351 //if( isPartyInRange() ) {
352 player->moveToLocator();
353 session->getMap()->center( toint( player->getX() ), toint( player->getY() ) );
354 }
355
356 // others follow the player
357 for ( int t = 0; t < getPartySize(); t++ ) {
358 if ( !party[t]->getStateMod( StateMod::dead ) && party[t] != player ) {
359 // If the non-leader is done moving try to follow again.
360 // This will be a no-op in follow() if we're close enough.
361 if ( !getParty( t )->anyMovesLeft() ) {
362 getParty( t )->follow( player );
363 }
364 // actually take a step
365 party[t]->moveToLocator();
366 }
367 }
368 }
369 }
370
getTotalLevel()371 int Party::getTotalLevel() {
372 int totalLevel = 0;
373 for ( int i = 0; i < getPartySize(); i++ )
374 totalLevel += getParty( i )->getLevel();
375 return totalLevel;
376 }
377
378 /**
379 Create a party programmatically until the party editor is made.
380 */
createHardCodedParty(Session * session,Creature ** pc,int * partySize)381 void Party::createHardCodedParty( Session *session, Creature **pc, int *partySize ) {
382 int pcCount = 4;
383 int level = 10;
384
385 // FIXME: consider using newCreature here
386 // the end of startMission would have to be modified to not delete the party
387 // also in scourge, where-ever creatureCount is used to mean all monsters would have
388 // to change (maybe that's a good thing too... same logic for party and monsters)
389 pc[0] = new Creature( session,
390 Character::getRandomCharacter(),
391 "Alamont",
392 Constants::SEX_MALE,
393 0 );
394 pc[0]->setLevel( level );
395 pc[0]->setExp();
396 pc[0]->setHp();
397 pc[0]->setMp();
398 pc[0]->setHunger( 8 );
399 pc[0]->setThirst( 7 );
400 pc[0]->setStateMod( StateMod::blessed, true );
401
402 pc[1] = new Creature( session,
403 Character::getRandomCharacter(),
404 "Barlett",
405 Constants::SEX_MALE,
406 0 );
407 pc[1]->setLevel( level );
408 pc[1]->setExp();
409 pc[1]->setHp();
410 pc[1]->setMp();
411 pc[1]->setHunger( 10 );
412 pc[1]->setThirst( 9 );
413 pc[1]->setStateMod( StateMod::drunk, true );
414 pc[1]->setStateMod( StateMod::cursed, true );
415
416 pc[2] = new Creature( session,
417 Character::getRandomCharacter(),
418 "Corinus",
419 Constants::SEX_FEMALE,
420 0 );
421 pc[2]->setLevel( level );
422 pc[2]->setExp();
423 pc[2]->setHp();
424 pc[2]->setMp();
425 pc[2]->setHunger( 3 );
426 pc[2]->setThirst( 2 );
427 pc[2]->setStateMod( StateMod::ac_protected, true );
428 pc[2]->setStateMod( StateMod::magic_protected, true );
429 pc[2]->setStateMod( StateMod::cursed, true );
430 // for(int i = 0; i < Constants::STATE_MOD_COUNT; i++)
431 // if(i != Constants::dead) pc[2]->setStateMod(i, true);
432
433 pc[3] = new Creature( session,
434 Character::getRandomCharacter(),
435 "Dialante",
436 Constants::SEX_FEMALE,
437 0 );
438 pc[3]->setLevel( level );
439 pc[3]->setExp();
440 pc[3]->setHp();
441 pc[3]->setMp();
442 pc[3]->setHunger( 10 );
443 pc[3]->setThirst( 10 );
444 //pc[3]->setStateMod(StateMod::possessed, true);
445
446 // compute starting skill levels
447 for ( int i = 0; i < pcCount; i++ ) {
448 for ( int skill = 0; skill < Skill::SKILL_COUNT; skill++ ) {
449 int n = level * Util::dice( 10 );
450 if ( n > 99 ) n = 99;
451 int maxSkill = pc[i]->getCharacter()->getSkill( skill );
452 if ( maxSkill >= 0 && n > maxSkill ) n = maxSkill;
453 pc[i]->setSkill( skill, n );
454 }
455 }
456
457 // add some items
458 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Bastard sword" ), level ) );
459 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Horned helmet" ), level ) );
460 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Dagger" ), level ) );
461 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
462 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
463 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Liquid armor" ), level ) );
464 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Speed" ), level ) );
465 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Coordination" ), level ) );
466 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Power" ), level ) );
467 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of IQ" ), level ) );
468 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Leadership" ), level ) );
469 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Luck" ), level ) );
470 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Piety" ), level ) );
471 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Potion of Lore" ), level ) );
472 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
473 pc[0]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
474
475 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Smallbow" ), level ) );
476 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Apple" ), level ) );
477 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Bread" ), level ) );
478 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Mushroom" ), level ) );
479 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Big egg" ), level ) );
480 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Mutton meat" ), level ) );
481 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
482 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
483 pc[1]->addToBackpack( session->newItem( RpgItem::getItemByName( "Liquid armor" ), level ) );
484
485 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Dagger" ), level ) );
486 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Smallbow" ), level ) );
487 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Long sword" ), level ) );
488 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Wine barrel" ), level ) );
489 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Mutton meat" ), level ) );
490 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
491 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
492 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
493 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
494 pc[2]->addToBackpack( session->newItem( RpgItem::getItemByName( "Liquid armor" ), level ) );
495
496 // add some scrolls
497 for ( int i = 0; i < 10; i++ ) {
498 Spell *spell = MagicSchool::getRandomSpell( 1 );
499 if ( spell ) {
500 RpgItem *rpgItem = RpgItem::getItemByName( "Scroll" );
501 Item *scroll = session->newItem( rpgItem, level );
502 scroll->setSpell( spell );
503 pc[2]->addToBackpack( scroll );
504 }
505 }
506 pc[2]->setMp( 50 );
507 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Dagger" ), level ) );
508 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Great sword" ), level ) );
509 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Battleaxe" ), level ) );
510 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Throwing axe" ), level ) );
511 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
512 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
513 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Health potion" ), level ) );
514 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
515 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Magic potion" ), level ) );
516 pc[3]->addToBackpack( session->newItem( RpgItem::getItemByName( "Liquid armor" ), level ) );
517 pc[3]->setMp( 500 );
518
519 // equip weapons
520 pc[0]->equipFromBackpack( 0 );
521 pc[0]->equipFromBackpack( 1 );
522 pc[1]->equipFromBackpack( 0 );
523 pc[2]->equipFromBackpack( 0 );
524 pc[2]->equipFromBackpack( 1 );
525 pc[3]->equipFromBackpack( 0 );
526
527 // add some spells
528 pc[2]->addSpell( Spell::getSpellByName( "Flame of Azun" ) );
529 pc[2]->addSpell( Spell::getSpellByName( "Ole Taffy's purty colors" ) );
530 pc[2]->addSpell( Spell::getSpellByName( "Silent knives" ) );
531 pc[2]->addSpell( Spell::getSpellByName( "Stinging light" ) );
532 pc[2]->addSpell( Spell::getSpellByName( "Burning stare" ) );
533
534 pc[3]->addSpell( Spell::getSpellByName( "Lesser healing touch" ) );
535 pc[3]->addSpell( Spell::getSpellByName( "Body of stone" ) );
536 pc[3]->addSpell( Spell::getSpellByName( "Bless group" ) );
537 pc[3]->addSpell( Spell::getSpellByName( "Invisibility" ) );
538 pc[3]->addSpell( Spell::getSpellByName( "Poison of ignorance" ) );
539 pc[3]->addSpell( Spell::getSpellByName( "Transmute poison" ) );
540 pc[3]->addSpell( Spell::getSpellByName( "Cursed ways" ) );
541 pc[3]->addSpell( Spell::getSpellByName( "Remove curse" ) );
542 pc[3]->addSpell( Spell::getSpellByName( "Enthrall fiend" ) );
543 pc[3]->addSpell( Spell::getSpellByName( "Break from possession" ) );
544
545 // assign random portraits
546 for ( int i = 0; i < pcCount; i++ ) {
547 pc[i]->setPortraitTextureIndex( Util::dice( session->getShapePalette()->getPortraitCount( pc[i]->getSex() ) ) );
548 }
549
550 *partySize = pcCount;
551 }
552
setParty(int count,Creature ** creatures,int storylineIndex)553 void Party::setParty( int count, Creature **creatures, int storylineIndex ) {
554 loadedCount = count;
555 for ( int i = 0; i < count; i++ ) loadedParty[i] = creatures[i];
556 this->storylineIndex = storylineIndex;
557 }
558
559 /// Return the closest live player within the given radius or null if none can be found.
560
getClosestPlayer(int x,int y,int w,int h,int radius)561 Creature *Party::getClosestPlayer( int x, int y, int w, int h, int radius ) {
562 float minDist = 0;
563 Creature *p = NULL;
564 for ( int i = 0; i < getPartySize(); i++ ) {
565 if ( !party[i]->getStateMod( StateMod::dead ) && !party[i]->getStateMod( StateMod::possessed ) ) {
566 float dist = Constants::distance( x, y, w, h, party[i]->getX(), party[i]->getY(), party[i]->getShape()->getWidth(),
567 party[i]->getShape()->getDepth() );
568 if ( dist <= static_cast<float>( radius ) && ( !p || dist < minDist ) ) {
569 p = party[i];
570 minDist = dist;
571 }
572 }
573 }
574 return p;
575 }
576
startEffect(int effect_type,int duration)577 void Party::startEffect( int effect_type, int duration ) {
578 for ( int i = 0; i < getPartySize(); i++ ) {
579 if ( !party[i]->getStateMod( StateMod::dead ) ) {
580 party[i]->startEffect( effect_type, duration );
581 }
582 }
583 }
584
setFormation(int formation)585 void Party::setFormation( int formation ) {
586 this->formation = formation;
587 for ( int i = 0; i < getPartySize(); i++ ) {
588 getParty( i )->setFormation( formation );
589 }
590 player_only = false;
591 startRound = true;
592 if ( !session->getGameAdapter()->isHeadless() )
593 session->getGameAdapter()->setFormationUI( formation, !isPlayerOnly() );
594 }
595
togglePlayerOnly(bool keepTargets)596 void Party::togglePlayerOnly( bool keepTargets ) {
597 player_only = ( player_only ? false : true );
598 // in group mode everyone hunts the same creature
599 if ( !player_only && !keepTargets ) {
600 for ( int i = 0; i < getPartySize(); i++ ) {
601 if ( party[i] != player )
602 party[i]->setTargetCreature( player->getTargetCreature() );
603 }
604 }
605 if ( player_only )
606 session->getGameAdapter()->writeLogMessage( Constants::getMessage( Constants::SINGLE_MODE ), Constants::MSGTYPE_SYSTEM );
607 else
608 session->getGameAdapter()->writeLogMessage( Constants::getMessage( Constants::GROUP_MODE ), Constants::MSGTYPE_SYSTEM );
609 if ( !session->getGameAdapter()->isHeadless() )
610 session->getGameAdapter()->togglePlayerOnlyUI( !isPlayerOnly() );
611 }
612
savePlayerSettings()613 void Party::savePlayerSettings() {
614 savedPlayer = player;
615 savedPlayerOnly = player_only;
616 }
617
restorePlayerSettings()618 void Party::restorePlayerSettings() {
619 if ( savedPlayer->getStateMod( StateMod::dead ) ) setFirstLivePlayer();
620 else if ( player != savedPlayer ) {
621 for ( int i = 0; i < getPartySize(); i++ ) {
622 if ( party[i] == savedPlayer ) {
623 setPlayer( i );
624 break;
625 }
626 }
627 }
628 if ( savedPlayerOnly != player_only ) togglePlayerOnly();
629 }
630
isEquipped(Item * item)631 bool Party::isEquipped( Item *item ) {
632 for ( int i = 0; i < getPartySize(); i++ ) {
633 if ( getParty( i )->isEquipped( item ) ) return true;
634 }
635 return false;
636 }
637
regainMp()638 void Party::regainMp() {
639 for ( int i = 0; i < getPartySize(); i++ ) {
640 if ( !getParty( i )->getStateMod( StateMod::dead ) &&
641 getParty( i )->getStartingMp() > 0 &&
642 getParty( i )->getMp() < getParty( i )->getMaxMp() ) {
643 getParty( i )->setMp( getParty( i )->getMp() + 1 );
644 }
645 }
646 }
647
applyRecurringSpecialSkills()648 void Party::applyRecurringSpecialSkills() {
649 for ( int i = 0; i < getPartySize(); i++ ) {
650 if ( !getParty( i )->getStateMod( StateMod::dead ) ) {
651 getParty( i )->applyRecurringSpecialSkills();
652 }
653 }
654 }
655
recomputeMaxSkills()656 void Party::recomputeMaxSkills() {
657 maxSkills.clear();
658 for ( int skill = 0; skill < Skill::SKILL_COUNT; skill++ ) {
659 int maxValue = 0;
660 Creature *maxPC = NULL;
661 for ( int i = 0; i < getPartySize(); i++ ) {
662 int value = getParty( i )->getSkill( skill );
663 if ( value > 0 && ( !maxPC || maxValue < value ) ) {
664 maxPC = getParty( i );
665 maxValue = value;
666 }
667 }
668 maxSkills.push_back(maxPC);
669 }
670 }
671
getAverageLevel()672 int Party::getAverageLevel() {
673 int sum = 0;
674 for ( int i = 0; i < getPartySize(); i++ ) {
675 sum += getParty( i )->getLevel();
676 }
677
678 if ( sum )
679 return static_cast<int>( sum / static_cast<float>( getPartySize() ) );
680 else
681 return 0;
682 }
683
hire(Creature * creature)684 void Party::hire( Creature *creature ) {
685 // Remove from the session list
686 assert( session->removeCreatureRef( creature, partySize ) );
687
688 // add to party
689 party[ partySize++ ] = creature;
690 partySet.insert( creature );
691
692 session->getSquirrel()->partyChanged();
693 }
694
dismiss(int index)695 void Party::dismiss( int index ) {
696 session->addCreatureRef( party[ index ], index );
697 for ( int i = index; i < partySize - 1; i++ ) {
698 party[ i ] = party[ i + 1 ];
699 }
700 party[ --partySize ] = NULL;
701 partySet.clear();
702 for ( int i = 0; i < partySize; i++ ) {
703 partySet.insert( party[i] );
704 }
705 session->getSquirrel()->partyChanged();
706 }
707
rollPerception()708 void Party::rollPerception() {
709 for ( int i = 0; i < getPartySize(); i++ ) {
710 getParty( i )->rollPerception();
711 }
712 }
713