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