1 /***************************************************************************
2               equip.cpp  -  Equipped items/spells/abilities widget
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 "equip.h"
20 #include "render/renderlib.h"
21 #include "rpg/rpglib.h"
22 #include "sound.h"
23 #include "sdlhandler.h"
24 #include "sdleventhandler.h"
25 #include "sdlscreenview.h"
26 #include "scourge.h"
27 #include "item.h"
28 #include "creature.h"
29 #include "tradedialog.h"
30 #include "uncursedialog.h"
31 #include "identifydialog.h"
32 #include "rechargedialog.h"
33 #include "sqbinding/sqbinding.h"
34 #include "characterinfo.h"
35 #include "shapepalette.h"
36 #include "skillsview.h"
37 #include "gui/confirmdialog.h"
38 #include "pcui.h"
39 #include "gui/scrollinglabel.h"
40 #include "storable.h"
41 
42 using namespace std;
43 
44 /**
45   *@author Gabor Torok
46   */
47 
48 #define SPELL_SIZE 30
49 #define DEBUG_SPECIAL_SKILL 0
50 
51 // fixme: this should be a property of the magicschool and should come from the .cfg file.
52 char *schoolIcons[] = {
53 	"nature", "divine", "life", "history", "tricks", "confrontation"
54 };
55 
Equip(PcUi * pcUi,int x,int y,int w,int h)56 Equip::Equip( PcUi *pcUi, int x, int y, int w, int h ) {
57 	this->pcUi = pcUi;
58 	this->creature = NULL;
59 	this->backgroundTexture = pcUi->getScourge()->getShapePalette()->getNamedTexture( "equip" );
60 	this->scrollTexture = pcUi->getScourge()->getShapePalette()->getNamedTexture( "scroll" );
61 	this->currentHole = -1;
62 	this->x = x;
63 	this->y = y;
64 	this->w = w;
65 	this->h = h;
66 	this->lastItem = NULL;
67 	this->mode = EQUIP_MODE;
68 	this->schoolIndex = -1;
69 	this->spellIndex = -1;
70 	this->specialSkill = NULL;
71 	this->storable = NULL;
72 
73 	canvas = new Canvas( x, y, x + w, y + h, this, this );
74 	canvas->setDrawBorders( false );
75 }
76 
~Equip()77 Equip::~Equip() {
78 }
79 
handleEvent(Widget * widget,SDL_Event * event)80 bool Equip::handleEvent( Widget *widget, SDL_Event *event ) {
81 	if ( widget == canvas ) {
82 		if ( pcUi->getScourge()->getSDLHandler()->isDoubleClick ) {
83 			if ( mode == EQUIP_MODE ) {
84 				Item *item = getItemAtPos( pcUi->getScourge()->getSDLHandler()->mouseX - pcUi->getWindow()->getX() - x,
85 				                           pcUi->getScourge()->getSDLHandler()->mouseY - pcUi->getWindow()->getY() - y - TITLE_HEIGHT );
86 				if ( item && item->getRpgItem()->isContainer() ) {
87 					pcUi->getScourge()->openContainerGui( item );
88 				}
89 			}
90 		} else if ( pcUi->getScourge()->getSDLHandler()->mouseButton == SDL_BUTTON_RIGHT ) {
91 			if ( mode == EQUIP_MODE ) {
92 				Item *item = getItemAtPos( pcUi->getScourge()->getSDLHandler()->mouseX - pcUi->getWindow()->getX() - x,
93 				                           pcUi->getScourge()->getSDLHandler()->mouseY - pcUi->getWindow()->getY() - y - TITLE_HEIGHT );
94 				if ( item ) {
95 					pcUi->getScourge()->getInfoGui()->setItem( item );
96 					if ( !pcUi->getScourge()->getInfoGui()->getWindow()->isVisible() )
97 						pcUi->getScourge()->getInfoGui()->getWindow()->setVisible( true );
98 				}
99 			} else if ( mode == SPELLS_MODE ) {
100 				int mx = pcUi->getScourge()->getSDLHandler()->mouseX - pcUi->getWindow()->getX() - x;
101 				int my = pcUi->getScourge()->getSDLHandler()->mouseY - pcUi->getWindow()->getY() - TITLE_HEIGHT;
102 				int si = getSchoolIndex( mx, my );
103 				int spi = getSpellIndex( mx, my, si );
104 				Spell *spell = ( si > -1 && spi > -1 ?
105 				                 MagicSchool::getMagicSchool( si )->getSpell( spi ) :
106 				                 NULL );
107 				if ( spell ) {
108 					pcUi->getScourge()->getInfoGui()->setSpell( spell );
109 					if ( !pcUi->getScourge()->getInfoGui()->getWindow()->isVisible() ) pcUi->getScourge()->getInfoGui()->getWindow()->setVisible( true );
110 				}
111 			} else if ( mode == CAPABILITIES_MODE ) {
112 				if ( specialSkill ) {
113 					pcUi->getScourge()->getInfoGui()->setSkill( specialSkill );
114 					if ( !pcUi->getScourge()->getInfoGui()->getWindow()->isVisible() ) pcUi->getScourge()->getInfoGui()->getWindow()->setVisible( true );
115 				}
116 			}
117 		} else if ( pcUi->getScourge()->getSDLHandler()->mouseButton == SDL_BUTTON_LEFT ) {
118 			if ( mode == SPELLS_MODE ) {
119 				// reset buttons first b/c it changes the cursor
120 				bool cast = pcUi->isCastSelected();
121 				bool store = pcUi->isStoreSpellSelected();
122 				if ( cast || store ) {
123 					pcUi->hide();
124 
125 					int mx = pcUi->getScourge()->getSDLHandler()->mouseX - pcUi->getWindow()->getX() - x;
126 					int my = pcUi->getScourge()->getSDLHandler()->mouseY - pcUi->getWindow()->getY() - TITLE_HEIGHT;
127 					int si = getSchoolIndex( mx, my );
128 					int spi = getSpellIndex( mx, my, si );
129 					Spell *spell = ( si > -1 && spi > -1 ?
130 					                 MagicSchool::getMagicSchool( si )->getSpell( spi ) :
131 					                 NULL );
132 					if ( spell ) {
133 						if ( cast ) {
134 							castSpell( spell );
135 						} else if ( store ) {
136 							storeSpell( spell );
137 						}
138 					}
139 				}
140 			} else if ( mode == CAPABILITIES_MODE ) {
141 				// reset buttons first b/c it changes the cursor
142 				bool cast = pcUi->isCastSelected();
143 				bool store = pcUi->isStoreSpellSelected();
144 				if ( cast || store ) {
145 					pcUi->hide();
146 
147 					if ( specialSkill ) {
148 						if ( cast ) {
149 							useSpecialSkill( specialSkill );
150 						} else if ( store ) {
151 							storeSpecialSkill( specialSkill );
152 						}
153 					}
154 				}
155 			}
156 		}
157 	}
158 	return false;
159 }
160 
handleEvent(SDL_Event * event)161 bool Equip::handleEvent( SDL_Event *event ) {
162 	int si, spi, mx, my;
163 	Item *item;
164 	Spell *spell;
165 	enum { TEXT_SIZE = 3000 };
166 	char tooltip[ TEXT_SIZE ], tmp[ TEXT_SIZE ];
167 	switch ( event->type ) {
168 	case SDL_MOUSEMOTION:
169 		mx = event->motion.x - pcUi->getWindow()->getX() - x;
170 		my = event->motion.y - pcUi->getWindow()->getY() - TITLE_HEIGHT;
171 		if ( mode == EQUIP_MODE ) {
172 			schoolIndex = spellIndex = -1;
173 			currentHole = getHoleAtPos( mx, my );
174 			item = getItemInHole( currentHole );
175 			if ( item != lastItem ) {
176 				lastItem = item;
177 				if ( item ) {
178 					item->getTooltip( tooltip );
179 					canvas->setTooltip( tooltip );
180 				} else {
181 					canvas->setTooltip( NULL );
182 				}
183 			}
184 		} else if ( mode == SPELLS_MODE ) {
185 			lastItem = NULL;
186 			si = getSchoolIndex( mx, my );
187 			spi = getSpellIndex( mx, my, si );
188 			if ( schoolIndex != si || spellIndex != spi ) {
189 				schoolIndex = si;
190 				spellIndex = spi;
191 				spell = ( schoolIndex > -1 && spellIndex > -1 ?
192 				          MagicSchool::getMagicSchool( schoolIndex )->getSpell( spellIndex ) :
193 				          NULL );
194 				if ( spell && creature && creature->isSpellMemorized( spell ) ) {
195 					Util::addLineBreaks( spell->getNotes(), tmp );
196 					snprintf( tooltip, TEXT_SIZE, "%s:|%s|%s:%d %s:%d",
197 					          spell->getDisplayName(),
198 					          tmp,
199 					          _( "Level" ), spell->getLevel(),
200 					          _( "MP Cost" ), spell->getMp() );
201 					canvas->setTooltip( tooltip );
202 				} else {
203 					canvas->setTooltip( "" );
204 				}
205 			}
206 		}
207 
208 		break;
209 	default: break;
210 	}
211 	return false;
212 }
213 
214 /*
215 // FIXME: brittle. This will break if drawCapabilities is changed.
216 SpecialSkill *Equip::findSpecialSkill( int x, int y ) {
217  int startX = 20;
218  int xx = startX;
219  int yy = 20;
220  yy += 5;
221  for( int i = 0; i < SpecialSkill::getSpecialSkillCount(); i++ ) {
222   SpecialSkill *ss = SpecialSkill::getSpecialSkill( i );
223   if( 1 || creature->hasSpecialSkill( ss ) ) {
224 
225   }
226  }
227 }
228 */
229 
230 /// Converts screen coordinates to a magic school (aka row in the spell list).
231 
getSchoolIndex(int x,int y)232 int Equip::getSchoolIndex( int x, int y ) {
233 	int n = ( y - 20 ) / 47;
234 	return( n >= 0 && n < MagicSchool::getMagicSchoolCount() ? n : -1 );
235 }
236 
237 /// Converts screen coordinates to a spell index.
238 
getSpellIndex(int x,int y,int schoolIndex)239 int Equip::getSpellIndex( int x, int y, int schoolIndex ) {
240 	int n = ( x - 20 ) / ( SPELL_SIZE + 2 );
241 	return( schoolIndex > -1 &&
242 	        n >= 0 &&
243 	        n < MagicSchool::getMagicSchool( schoolIndex )->getSpellCount() ? n : -1 );
244 }
245 
246 /// Returns the item at an equip index.
247 
getItemInHole(int hole)248 Item *Equip::getItemInHole( int hole ) {
249 	return( hole > -1 && creature ? creature->getEquippedItemByIndex( hole ) : NULL );
250 }
251 
252 /// Takes screen coordinates and determines which equipped item these point at.
253 
getItemAtPos(int x,int y)254 Item *Equip::getItemAtPos( int x, int y ) {
255 	int hole = getHoleAtPos( x, y );
256 	return getItemInHole( hole );
257 }
258 
259 /// Converts a screen coordinate to an equip index.
260 
getHoleAtPos(int x,int y)261 int Equip::getHoleAtPos( int x, int y ) {
262 	SDL_Rect point;
263 	point.x = x;
264 	point.y = y;
265 	point.w = point.h = 1;
266 	for ( int i = 0; i < Constants::EQUIP_LOCATION_COUNT; i++ ) {
267 		SDL_Rect *rect = pcUi->getScourge()->getShapePalette()->getEquipHole( i );
268 		if ( SDLHandler::intersects( rect, &point ) ) {
269 			return i;
270 		}
271 	}
272 	return -1;
273 }
274 
275 /// Handles dragging items onto the paperdoll.
276 
receive(Widget * widget)277 void Equip::receive( Widget *widget ) {
278 	if ( mode == EQUIP_MODE && creature ) {
279 		Item *item = pcUi->getScourge()->getMovingItem();
280 		if ( item ) {
281 			char *err = creature->canEquipItem( item );
282 			if ( err ) {
283 				pcUi->getScourge()->showMessageDialog( err );
284 				pcUi->getScourge()->getSession()->getSound()->playSound( Window::DROP_FAILED, 127 );
285 			} else {
286 				if ( creature->addToBackpack( item ) ) {
287 					// message: the player accepted the item
288 					char message[120];
289 					snprintf( message, 119, _( "%s picks up %s." ),
290 					          creature->getName(),
291 					          item->getItemName() );
292 					pcUi->getScourge()->writeLogMessage( message );
293 					pcUi->getScourge()->endItemDrag();
294 					int index = creature->findInBackpack( item );
295 					creature->equipFromBackpack( index, currentHole );
296 					pcUi->getScourge()->getSession()->getSound()->playSound( Window::DROP_SUCCESS, 127 );
297 				} else {
298 					// message: the player's backpack is full
299 					pcUi->getScourge()->getSession()->getSound()->playSound( Window::DROP_FAILED, 127 );
300 					pcUi->getScourge()->showMessageDialog( _( "You can't fit the item!" ) );
301 				}
302 			}
303 		}
304 	}
305 }
306 
307 /// Handles picking up of items from the paperdoll.
308 
startDrag(Widget * widget,int x,int y)309 bool Equip::startDrag( Widget *widget, int x, int y ) {
310 	if ( mode == EQUIP_MODE && creature ) {
311 
312 		if ( pcUi->getScourge()->getTradeDialog()->getWindow()->isVisible() ) {
313 			pcUi->getScourge()->showMessageDialog( _( "Can't change backpack while trading." ) );
314 			return false;
315 		} else if ( pcUi->getScourge()->getUncurseDialog()->getWindow()->isVisible() ) {
316 			pcUi->getScourge()->showMessageDialog( _( "Can't change backpack while employing a sage's services." ) );
317 			return false;
318 		} else if ( pcUi->getScourge()->getIdentifyDialog()->getWindow()->isVisible() ) {
319 			pcUi->getScourge()->showMessageDialog( _( "Can't change backpack while employing a sage's services." ) );
320 			return false;
321 		} else if ( pcUi->getScourge()->getRechargeDialog()->getWindow()->isVisible() ) {
322 			pcUi->getScourge()->showMessageDialog( _( "Can't change backpack while employing a sage's services." ) );
323 			return false;
324 		}
325 
326 		// what's equipped at this slot?
327 		currentHole = getHoleAtPos( x, y );
328 		Item *item = getItemAtPos( x, y );
329 		if ( item ) {
330 			if ( item->isCursed() ) {
331 				pcUi->getScourge()->showMessageDialog( _( "Can't remove cursed item!" ) );
332 				return false;
333 			} else {
334 				creature->removeFromBackpack( creature->findInBackpack( item ) );
335 				pcUi->getScourge()->startItemDragFromGui( item );
336 				char message[120];
337 				snprintf( message, 119, _( "%s drops %s." ),
338 				          creature->getName(),
339 				          item->getItemName() );
340 				pcUi->getScourge()->writeLogMessage( message );
341 
342 				return true;
343 			}
344 		}
345 	}
346 	return false;
347 }
348 
setCreature(Creature * creature)349 void Equip::setCreature( Creature *creature ) {
350 	this->creature = creature;
351 }
352 
drawWidgetContents(Widget * widget)353 void Equip::drawWidgetContents( Widget *widget ) {
354 	glEnable( GL_TEXTURE_2D );
355 	// glEnable( GL_ALPHA_TEST );
356 	// glAlphaFunc( GL_NOTEQUAL, 0 );
357 	glEnable( GL_BLEND );
358 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
359 	if ( mode == EQUIP_MODE ) {
360 		backgroundTexture.glBind();
361 	} else {
362 		scrollTexture.glBind();
363 	}
364 	glColor4f( 1, 1, 1, 1 );
365 	glBegin( GL_TRIANGLE_STRIP );
366 	glTexCoord2d( 0, 0 );
367 	glVertex2d( 0, 0 );
368 	glTexCoord2d( 1, 0 );
369 	glVertex2d( w, 0 );
370 	glTexCoord2d( 0, 1 );
371 	glVertex2d( 0, h );
372 	glTexCoord2d( 1, 1 );
373 	glVertex2d( w, h );
374 	glEnd();
375 	glDisable( GL_BLEND );
376 	// glDisable( GL_ALPHA_TEST );
377 	if ( creature ) {
378 		if ( mode == EQUIP_MODE ) {
379 			drawEquipment();
380 		} else if ( mode == SPELLS_MODE ) {
381 			drawSpells();
382 		} else {
383 			drawCapabilities();
384 		}
385 	}
386 }
387 
388 /// Draws the paperdoll with the equipped items.
389 
drawEquipment()390 void Equip::drawEquipment() {
391 	for ( int i = 0; i < Constants::EQUIP_LOCATION_COUNT; i++ ) {
392 		SDL_Rect *rect = pcUi->getScourge()->getShapePalette()->getEquipHole( i );
393 		Item *item = creature->getEquippedItemByIndex( i );
394 		if ( item ) {
395 			if ( rect && rect->w && rect->h ) {
396 				glEnable( GL_TEXTURE_2D );
397 				item->renderIcon( pcUi->getScourge(), rect );
398 			}
399 		}
400 	}
401 	if ( currentHole > -1 ) {
402 		SDL_Rect *rect = pcUi->getScourge()->getShapePalette()->getEquipHole( currentHole );
403 		glDisable( GL_TEXTURE_2D );
404 		pcUi->getWindow()->setTopWindowBorderColor();
405 		glBegin( GL_LINE_LOOP );
406 		glVertex2d( rect->x, rect->y + rect->h );
407 		glVertex2d( rect->x, rect->y );
408 		glVertex2d( rect->x + rect->w, rect->y );
409 		glVertex2d( rect->x + rect->w, rect->y + rect->h );
410 		glEnd();
411 	}
412 }
413 
414 /// Draws the spell list.
415 
drawSpells()416 void Equip::drawSpells() {
417 	int startX = 20;
418 	int xx = startX;
419 	int yy = 20;
420 
421 	glEnable( GL_BLEND );
422 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
423 
424 	for ( int i = 0; i < MagicSchool::getMagicSchoolCount(); i++ ) {
425 		MagicSchool *school = MagicSchool::getMagicSchool( i );
426 
427 		glPushMatrix();
428 		glTranslatef( xx, yy - 12, 0 );
429 
430 		int size = 15;
431 		int width = w - 55;
432 
433 		glDisable( GL_TEXTURE_2D );
434 		glColor4f( 0, 0, 0, 0.75 );
435 		glBegin( GL_TRIANGLE_STRIP );
436 		glVertex2d( 0, 1 );
437 		glVertex2d( size + width, 1 );
438 		glVertex2d( 0, size );
439 		glVertex2d( size + width, size );
440 		glEnd();
441 		glEnable( GL_TEXTURE_2D );
442 
443 		pcUi->getScourge()->getShapePalette()->getNamedTexture( schoolIcons[ i ] ).glBind();
444 		glColor4f( 1, 1, 1, 1 );
445 		glBegin( GL_TRIANGLE_STRIP );
446 		glTexCoord2d( 0, 0 );
447 		glVertex2d( 0, 0 );
448 		glTexCoord2d( 1, 0 );
449 		glVertex2d( size, 0 );
450 		glTexCoord2d( 0, 1 );
451 		glVertex2d( 0, size );
452 		glTexCoord2d( 1, 1 );
453 		glVertex2d( size, size );
454 		glEnd();
455 
456 		glColor4f( 1, 0.35f, 0, 1 );
457 		pcUi->getScourge()->getSDLHandler()->setFontType( Constants::SCOURGE_MONO_FONT );
458 		pcUi->getScourge()->getSDLHandler()->texPrint( size + 5, 13, school->getDisplayName() );
459 		pcUi->getScourge()->getSDLHandler()->setFontType( Constants::SCOURGE_DEFAULT_FONT );
460 
461 		glPopMatrix();
462 
463 		yy += 5;
464 		for ( int t = 0; t < school->getSpellCount(); t++, xx += SPELL_SIZE + 2 ) {
465 			Spell *spell = school->getSpell( t );
466 			if ( creature && creature->isSpellMemorized( spell ) ) {
467 				pcUi->getScourge()->getShapePalette()->spellsTex[ spell->getIconTileX() ][ spell->getIconTileY() ].glBind();
468 				glColor4f( 1, 1, 1, 1 );
469 				glBegin( GL_TRIANGLE_STRIP );
470 				glTexCoord2d( 0, 0 );
471 				glVertex2d( xx, yy );
472 				glTexCoord2d( 1, 0 );
473 				glVertex2d( xx + SPELL_SIZE, yy );
474 				glTexCoord2d( 0, 1 );
475 				glVertex2d( xx, yy + SPELL_SIZE );
476 				glTexCoord2d( 1, 1 );
477 				glVertex2d( xx + SPELL_SIZE, yy + SPELL_SIZE );
478 				glEnd();
479 			}
480 			if ( schoolIndex == i && spellIndex == t ) {
481 				glColor4f( 1, 1, 0, 1 );
482 			} else {
483 				pcUi->getWindow()->setTopWindowBorderColor();
484 			}
485 			glDisable( GL_TEXTURE_2D );
486 			glBegin( GL_LINE_LOOP );
487 			glVertex2d( xx, yy + SPELL_SIZE );
488 			glVertex2d( xx, yy );
489 			glVertex2d( xx + SPELL_SIZE, yy );
490 			glVertex2d( xx + SPELL_SIZE, yy + SPELL_SIZE );
491 			glEnd();
492 			glEnable( GL_TEXTURE_2D );
493 		}
494 
495 		xx = startX;
496 		yy += SPELL_SIZE + 12;
497 	}
498 	glDisable( GL_BLEND );
499 }
500 
501 /// Draws the list of special capabilities.
502 
drawCapabilities()503 void Equip::drawCapabilities() {
504 	int startX = 20;
505 	int xx = startX;
506 	int yy = 20;
507 
508 	glPushMatrix();
509 	glTranslatef( xx, yy - 12, 0 );
510 
511 	int size = 15;
512 	int width = w - 55;
513 
514 	glEnable( GL_BLEND );
515 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
516 	glDisable( GL_TEXTURE_2D );
517 
518 	glColor4f( 0, 0, 0, 0.75 );
519 	glBegin( GL_TRIANGLE_STRIP );
520 	glVertex2d( 0, 1 );
521 	glVertex2d( size + width, 1 );
522 	glVertex2d( 0, size );
523 	glVertex2d( size + width, size );
524 	glEnd();
525 
526 	glEnable( GL_TEXTURE_2D );
527 
528 	glColor4f( 1, 0.35f, 0, 1 );
529 	pcUi->getScourge()->getSDLHandler()->setFontType( Constants::SCOURGE_MONO_FONT );
530 	pcUi->getScourge()->getSDLHandler()->texPrint( size + 5, 13, _( "Special Capabilities" ) );
531 	pcUi->getScourge()->getSDLHandler()->setFontType( Constants::SCOURGE_DEFAULT_FONT );
532 
533 	glPopMatrix();
534 
535 	int mx = pcUi->getScourge()->getSDLHandler()->mouseX - pcUi->getWindow()->getX() - x;
536 	int my = pcUi->getScourge()->getSDLHandler()->mouseY - pcUi->getWindow()->getY() - TITLE_HEIGHT;
537 
538 	yy += 5;
539 	bool found = false;
540 	for ( int i = 0; i < SpecialSkill::getSpecialSkillCount(); i++ ) {
541 		SpecialSkill *ss = SpecialSkill::getSpecialSkill( i );
542 		if ( DEBUG_SPECIAL_SKILL || creature->hasSpecialSkill( ss ) ) {
543 
544 			if ( !found &&
545 			        mx >= xx && mx < xx + SPELL_SIZE &&
546 			        yy >= yy && my < yy + SPELL_SIZE ) {
547 				if ( specialSkill != ss ) {
548 					specialSkill = ss;
549 					enum { TEXT_SIZE = 3000 };
550 					char tmp[ TEXT_SIZE ], tooltip[ TEXT_SIZE ];
551 					Util::addLineBreaks( ss->getDescription(), tmp );
552 					snprintf( tooltip, TEXT_SIZE, "%s:|%s|%s",
553 					          ss->getDisplayName(),
554 					          tmp,
555 					          ss->getType() == SpecialSkill::SKILL_TYPE_MANUAL ?
556 					          _( "Manual Capability" ) :
557 					          _( "Automatic Capability" ) );
558 					canvas->setTooltip( tooltip );
559 				}
560 				found = true;
561 			}
562 
563 			pcUi->getScourge()->getShapePalette()->spellsTex[ ss->getIconTileX() ][ ss->getIconTileY() ].glBind();
564 			glColor4f( 1, 1, 1, 1 );
565 			glBegin( GL_TRIANGLE_STRIP );
566 			glTexCoord2d( 0, 0 );
567 			glVertex2d( xx, yy );
568 			glTexCoord2d( 1, 0 );
569 			glVertex2d( xx + SPELL_SIZE, yy );
570 			glTexCoord2d( 0, 1 );
571 			glVertex2d( xx, yy + SPELL_SIZE );
572 			glTexCoord2d( 1, 1 );
573 			glVertex2d( xx + SPELL_SIZE, yy + SPELL_SIZE );
574 			glEnd();
575 
576 			if ( specialSkill == ss ) {
577 				glColor4f( 1, 1, 0, 1 );
578 			} else {
579 				pcUi->getWindow()->setTopWindowBorderColor();
580 			}
581 			glDisable( GL_TEXTURE_2D );
582 			glBegin( GL_LINE_LOOP );
583 			glVertex2d( xx, yy + SPELL_SIZE );
584 			glVertex2d( xx, yy );
585 			glVertex2d( xx + SPELL_SIZE, yy );
586 			glVertex2d( xx + SPELL_SIZE, yy + SPELL_SIZE );
587 			glEnd();
588 			glEnable( GL_TEXTURE_2D );
589 
590 			xx += SPELL_SIZE + 2;
591 			if ( xx > w - 50 ) {
592 				xx = startX;
593 				yy += SPELL_SIZE + 2;
594 			}
595 		}
596 	}
597 	if ( !found ) {
598 		specialSkill = NULL;
599 		canvas->setTooltip( "" );
600 	}
601 	glDisable( GL_BLEND );
602 }
603 
604 /// Using a special capability from the list.
605 
useSpecialSkill(SpecialSkill * ss)606 void Equip::useSpecialSkill( SpecialSkill *ss ) {
607 	if ( ss && ( DEBUG_SPECIAL_SKILL || creature->hasSpecialSkill( ss ) ) ) {
608 		if ( ss->getType() != SpecialSkill::SKILL_TYPE_MANUAL ) {
609 			pcUi->getScourge()->showMessageDialog( _( "Only manual type capabilities can be used this way." ) );
610 		} else {
611 
612 			creature->setAction( Constants::ACTION_SPECIAL, NULL, NULL, ss );
613 			creature->setTargetCreature( creature );
614 
615 			// set this as a quickspell if there is space
616 			for ( int i = 0; i < 12; i++ ) {
617 				if ( !creature->getQuickSpell( i ) ) {
618 					creature->setQuickSpell( i, ss );
619 					break;
620 				}
621 			}
622 		}
623 	}
624 }
625 
626 /// Casting a spell from the spell list.
627 
castSpell(Spell * spell)628 void Equip::castSpell( Spell *spell ) {
629 	if ( spell ) {
630 		if ( spell->getMp() > creature->getMp() ) {
631 			pcUi->getScourge()->showMessageDialog( _( "Not enough Magic Points to cast this spell!" ) );
632 		} else {
633 			// set this as a quickspell if there is space
634 			for ( int i = 0; i < 12; i++ ) {
635 				if ( !creature->getQuickSpell( i ) ) {
636 					creature->setQuickSpell( i, spell );
637 					break;
638 				}
639 			}
640 
641 			creature->setAction( Constants::ACTION_CAST_SPELL, NULL, spell );
642 			if ( !spell->isPartyTargetAllowed() ) {
643 				pcUi->getScourge()->setTargetSelectionFor( creature );
644 			} else {
645 				creature->setTargetCreature( creature );
646 			}
647 		}
648 	}
649 }
650 
651 /// Handles storing a spell in a quickspell slot.
652 
storeSpell(Spell * spell)653 void Equip::storeSpell( Spell *spell ) {
654 	if ( spell ) {
655 		storeStorable( ( Storable* )spell );
656 	}
657 }
658 
659 /// Handles storing a special capability in a quickspell slot.
660 
storeSpecialSkill(SpecialSkill * ss)661 void Equip::storeSpecialSkill( SpecialSkill *ss ) {
662 	if ( ss && ( DEBUG_SPECIAL_SKILL || creature->hasSpecialSkill( ss ) ) ) {
663 		if ( ss->getType() != SpecialSkill::SKILL_TYPE_MANUAL ) {
664 			pcUi->getScourge()->showMessageDialog( _( "Only manual type capabilities can be stored." ) );
665 		} else {
666 			storeStorable( ( Storable* )ss );
667 		}
668 	}
669 }
670 
671 /// Stores a spell or special capability in a quickspell slot.
672 
storeStorable(Storable * storable)673 void Equip::storeStorable( Storable *storable ) {
674 	this->storable = NULL;
675 	const char *p = storable->isStorable();
676 	if ( p ) {
677 		pcUi->getScourge()->showMessageDialog( p );
678 	} else {
679 		this->storable = storable;
680 		pcUi->getScourge()->showMessageDialog( _( "Click a quickspell slot to store this spell." ) );
681 	}
682 }
683 
MissionInfoUI(PcUi * pcUi,int x,int y,int w,int h)684 MissionInfoUI::MissionInfoUI( PcUi *pcUi, int x, int y, int w, int h ) {
685 	this->pcUi = pcUi;
686 	this->x = x;
687 	this->y = y;
688 	this->w = w;
689 	this->h = h;
690 
691 	description = new ScrollingLabel( x, y, w, h - 95, "" );
692 	pcUi->getWindow()->addWidget( description );
693 
694 	objectivesLabel = pcUi->getWindow()->createLabel( x, y + h - 80, _( "Mission Objectives" ) );
695 	objectiveList = new ScrollingList( x, y + h - 75, w, 45, pcUi->getScourge()->getShapePalette()->getHighlightTexture() );
696 	pcUi->getWindow()->addWidget( objectiveList );
697 	consoleButton = pcUi->getWindow()->createButton( x, y + h - 25, x + w, y + h - 5, _( "Show Squirrel Console" ) );
698 }
699 
~MissionInfoUI()700 MissionInfoUI::~MissionInfoUI() {
701 	// objectiveText has static size now
702 }
703 
refresh()704 void MissionInfoUI::refresh() {
705 	enum { TMP_SIZE = 80, MISSNTXT_SIZE = 3000 };
706 	Color green( 0.2f, 0.7f, 0.2f ), red( 0.7f, 0.2f, 0.2f );
707 	char missionText[MISSNTXT_SIZE], tmp[TMP_SIZE];
708 	Scourge *scourge = pcUi->getScourge();
709 	Mission* curMission = scourge->getSession()->getCurrentMission();
710 	objectiveText.clear();
711 	missionColor.clear();
712 
713 	if ( curMission ) {
714 		snprintf( tmp, TMP_SIZE, _( "Depth: %d out of %d." ), ( scourge->getCurrentDepth() + 1 ), curMission->getDepth() );
715 		snprintf( missionText, MISSNTXT_SIZE, "%s:|%s|%s", curMission->getDisplayName(), tmp, curMission->getDescription() );
716 
717 		for ( int t = 0; t < curMission->getItemCount(); t++ ) {
718 			snprintf( tmp, TMP_SIZE, _( "Find %s" ), curMission->getItem( t )->getDisplayName() );
719 			if ( curMission->getItemHandled( t ) ) {
720 				objectiveText.push_back( tmp + string( ". " ) + _( "(completed)" ) );
721 				missionColor.push_back( green );
722 			} else {
723 				objectiveText.push_back( tmp + string( ". " ) + _( "(not yet found)" ) );
724 				missionColor.push_back( red );
725 			}
726 		}
727 
728 		for ( int t = 0; t < curMission->getCreatureCount(); t++ ) {
729 			snprintf( tmp, TMP_SIZE, _( "Vanquish %s." ), curMission->getCreature( t )->getDisplayName() );
730 			if ( curMission->getCreatureHandled( t ) ) {
731 				objectiveText.push_back( tmp + string( ". " ) + _( "(completed)" ) );
732 				missionColor.push_back( green );
733 			} else {
734 				objectiveText.push_back( tmp + string( ". " ) + _( "(not yet done)" ) );
735 				missionColor.push_back( red );
736 			}
737 		}
738 
739 		if ( objectiveText.size() == 0 && curMission->isCompleted() ) {
740 			objectiveText.push_back( _( "Special" ) + string( ". " ) + _( "(completed)" ) );
741 			missionColor.push_back( green );
742 		} else if ( objectiveText.size() == 0 ) {
743 			objectiveText.push_back( _( "Special" ) + string( ". " ) + _( "(not yet done)" ) );
744 			missionColor.push_back( red );
745 		}
746 		objectiveList->setLines( objectiveText.begin(), objectiveText.end(), &missionColor[0] );
747 	} else {
748 		strncpy( missionText, _( "No current mission." ), MISSNTXT_SIZE );
749 	}
750 	description->setText( missionText );
751 }
752 
show()753 void MissionInfoUI::show() {
754 	description->setVisible( true );
755 	objectiveList->setVisible( true );
756 	objectivesLabel->setVisible( true );
757 	consoleButton->setVisible( true );
758 }
759 
hide()760 void MissionInfoUI::hide() {
761 	description->setVisible( false );
762 	objectiveList->setVisible( false );
763 	objectivesLabel->setVisible( false );
764 	consoleButton->setVisible( false );
765 }
766 
767