doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GameBustOutWindow.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 #include "../idlib/precompiled.h"
29 #pragma hdrstop
30 
31 #include "../framework/Session_local.h"
32 #include "../renderer/Image.h"
33 
34 #include "DeviceContext.h"
35 #include "Window.h"
36 #include "UserInterfaceLocal.h"
37 #include "GameBustOutWindow.h"
38 
39 #define BALL_RADIUS 12.f
40 #define BALL_SPEED 250.f
41 #define BALL_MAXSPEED 450.f
42 
43 #define S_UNIQUE_CHANNEL 6
44 
45 /*
46 *****************************************************************************
47 * BOEntity
48 ****************************************************************************
49 */
51  game = _game;
52  visible = true;
53 
54  materialName = "";
55  material = NULL;
56  width = height = 8;
57  color = colorWhite;
59 
60  position.Zero();
61  velocity.Zero();
62 
63  removed = false;
64  fadeOut = 0;
65 }
66 
68 }
69 
70 /*
71 ======================
72 BOEntity::WriteToSaveGame
73 ======================
74 */
75 void BOEntity::WriteToSaveGame( idFile *savefile ) {
76 
77  savefile->Write( &visible, sizeof(visible) );
78 
80 
81  savefile->Write( &width, sizeof(width) );
82  savefile->Write( &height, sizeof(height) );
83 
84  savefile->Write( &color, sizeof(color) );
85  savefile->Write( &position, sizeof(position) );
86  savefile->Write( &velocity, sizeof(velocity) );
87 
88  savefile->Write( &powerup, sizeof(powerup) );
89  savefile->Write( &removed, sizeof(removed) );
90  savefile->Write( &fadeOut, sizeof(fadeOut) );
91 }
92 
93 /*
94 ======================
95 BOEntity::ReadFromSaveGame
96 ======================
97 */
99  game = _game;
100 
101  savefile->Read( &visible, sizeof(visible) );
102 
103  game->ReadSaveGameString( materialName, savefile );
105 
106  savefile->Read( &width, sizeof(width) );
107  savefile->Read( &height, sizeof(height) );
108 
109  savefile->Read( &color, sizeof(color) );
110  savefile->Read( &position, sizeof(position) );
111  savefile->Read( &velocity, sizeof(velocity) );
112 
113  savefile->Read( &powerup, sizeof(powerup) );
114  savefile->Read( &removed, sizeof(removed) );
115  savefile->Read( &fadeOut, sizeof(fadeOut) );
116 }
117 
118 /*
119 ======================
120 BOEntity::SetMaterial
121 ======================
122 */
123 void BOEntity::SetMaterial(const char* name) {
124  materialName = name;
125  material = declManager->FindMaterial( name );
126  material->SetSort( SS_GUI );
127 }
128 
129 /*
130 ======================
131 BOEntity::SetSize
132 ======================
133 */
134 void BOEntity::SetSize( float _width, float _height ) {
135  width = _width;
136  height = _height;
137 }
138 
139 /*
140 ======================
141 BOEntity::SetVisible
142 ======================
143 */
144 void BOEntity::SetColor( float r, float g, float b, float a ) {
145  color.x = r;
146  color.y = g;
147  color.z = b;
148  color.w = a;
149 }
150 
151 /*
152 ======================
153 BOEntity::SetVisible
154 ======================
155 */
156 void BOEntity::SetVisible( bool isVisible ) {
157  visible = isVisible;
158 }
159 
160 /*
161 ======================
162 BOEntity::Update
163 ======================
164 */
165 void BOEntity::Update( float timeslice, int guiTime ) {
166 
167  if ( !visible ) {
168  return;
169  }
170 
171  // Move the entity
172  position += velocity * timeslice;
173 
174  // Fade out the ent
175  if ( fadeOut ) {
176  color.w -= timeslice * 2.5;
177 
178  if ( color.w <= 0.f ) {
179  color.w = 0.f;
180  removed = true;
181  }
182  }
183 }
184 
185 /*
186 ======================
187 BOEntity::Draw
188 ======================
189 */
191  if ( visible ) {
192  dc->DrawMaterialRotated( position.x, position.y, width, height, material, color, 1.0f, 1.0f, DEG2RAD(0.f) );
193  }
194 }
195 
196 /*
197 *****************************************************************************
198 * BOBrick
199 ****************************************************************************
200 */
202  ent = NULL;
203  x = y = width = height = 0;
205  isBroken = false;
206 }
207 
208 BOBrick::BOBrick( BOEntity *_ent, float _x, float _y, float _width, float _height ) {
209  ent = _ent;
210  x = _x;
211  y = _y;
212  width = _width;
213  height = _height;
215 
216  isBroken = false;
217 
218  ent->position.x = x;
219  ent->position.y = y;
220  ent->SetSize( width, height );
221  ent->SetMaterial( "game/bustout/brick" );
222 
223  ent->game->entities.Append( ent );
224 }
225 
227 }
228 
229 /*
230 ======================
231 BOBrick::WriteToSaveGame
232 ======================
233 */
234 void BOBrick::WriteToSaveGame( idFile *savefile ) {
235  savefile->Write( &x, sizeof(x) );
236  savefile->Write( &y, sizeof(y) );
237  savefile->Write( &width, sizeof(width) );
238  savefile->Write( &height, sizeof(height) );
239 
240  savefile->Write( &powerup, sizeof(powerup) );
241  savefile->Write( &isBroken, sizeof(isBroken) );
242 
243  int index = ent->game->entities.FindIndex( ent );
244  savefile->Write( &index, sizeof(index) );
245 }
246 
247 /*
248 ======================
249 BOBrick::ReadFromSaveGame
250 ======================
251 */
253  savefile->Read( &x, sizeof(x) );
254  savefile->Read( &y, sizeof(y) );
255  savefile->Read( &width, sizeof(width) );
256  savefile->Read( &height, sizeof(height) );
257 
258  savefile->Read( &powerup, sizeof(powerup) );
259  savefile->Read( &isBroken, sizeof(isBroken) );
260 
261  int index;
262  savefile->Read( &index, sizeof(index) );
263  ent = game->entities[index];
264 }
265 
266 /*
267 ======================
268 BOBrick::SetColor
269 ======================
270 */
271 void BOBrick::SetColor( idVec4 bcolor ) {
272  ent->SetColor( bcolor.x, bcolor.y, bcolor.z, bcolor.w );
273 }
274 
275 /*
276 ======================
277 BOBrick::checkCollision
278 ======================
279 */
281  idVec2 ptA, ptB;
282  float dist;
283 
285 
286  if ( isBroken ) {
287  return result;
288  }
289 
290  // Check for collision with each edge
291  idVec2 vec;
292 
293  // Bottom
294  ptA.x = x;
295  ptA.y = y + height;
296 
297  ptB.x = x + width;
298  ptB.y = y + height;
299 
300  if ( vel.y < 0 && pos.y > ptA.y ) {
301  if( pos.x > ptA.x && pos.x < ptB.x ) {
302  dist = pos.y - ptA.y;
303 
304  if ( dist < BALL_RADIUS ) {
305  result = COLLIDE_DOWN;
306  }
307  } else {
308  if ( pos.x <= ptA.x ) {
309  vec = pos - ptA;
310  } else {
311  vec = pos - ptB;
312  }
313 
314  if ( (idMath::Fabs(vec.y) > idMath::Fabs(vec.x)) && (vec.LengthFast() < BALL_RADIUS) ) {
315  result = COLLIDE_DOWN;
316  }
317  }
318  }
319 
320  if ( result == COLLIDE_NONE ) {
321  // Top
322  ptA.y = y;
323  ptB.y = y;
324 
325  if ( vel.y > 0 && pos.y < ptA.y ) {
326  if( pos.x > ptA.x && pos.x < ptB.x ) {
327  dist = ptA.y - pos.y;
328 
329  if ( dist < BALL_RADIUS ) {
330  result = COLLIDE_UP;
331  }
332  } else {
333  if ( pos.x <= ptA.x ) {
334  vec = pos - ptA;
335  } else {
336  vec = pos - ptB;
337  }
338 
339  if ( (idMath::Fabs(vec.y) > idMath::Fabs(vec.x)) && (vec.LengthFast() < BALL_RADIUS) ) {
340  result = COLLIDE_UP;
341  }
342  }
343  }
344 
345  if ( result == COLLIDE_NONE ) {
346  // Left side
347  ptA.x = x;
348  ptA.y = y;
349 
350  ptB.x = x;
351  ptB.y = y + height;
352 
353  if ( vel.x > 0 && pos.x < ptA.x ) {
354  if( pos.y > ptA.y && pos.y < ptB.y ) {
355  dist = ptA.x - pos.x;
356 
357  if ( dist < BALL_RADIUS ) {
358  result = COLLIDE_LEFT;
359  }
360  } else {
361  if ( pos.y <= ptA.y ) {
362  vec = pos - ptA;
363  } else {
364  vec = pos - ptB;
365  }
366 
367  if ( (idMath::Fabs(vec.x) >= idMath::Fabs(vec.y)) && (vec.LengthFast() < BALL_RADIUS) ) {
368  result = COLLIDE_LEFT;
369  }
370  }
371  }
372 
373  if ( result == COLLIDE_NONE ) {
374  // Right side
375  ptA.x = x + width;
376  ptB.x = x + width;
377 
378  if ( vel.x < 0 && pos.x > ptA.x ) {
379  if( pos.y > ptA.y && pos.y < ptB.y ) {
380  dist = pos.x - ptA.x;
381 
382  if ( dist < BALL_RADIUS ) {
383  result = COLLIDE_LEFT;
384  }
385  } else {
386  if ( pos.y <= ptA.y ) {
387  vec = pos - ptA;
388  } else {
389  vec = pos - ptB;
390  }
391 
392  if ( (idMath::Fabs(vec.x) >= idMath::Fabs(vec.y)) && (vec.LengthFast() < BALL_RADIUS) ) {
393  result = COLLIDE_LEFT;
394  }
395  }
396  }
397 
398  }
399  }
400  }
401 
402  return result;
403 }
404 
405 /*
406 *****************************************************************************
407 * idGameBustOutWindow
408 ****************************************************************************
409 */
411  dc = d;
412  gui = g;
413  CommonInit();
414 }
415 
417  gui = g;
418  CommonInit();
419 }
420 
422  entities.DeleteContents(true);
423 
425 }
426 
427 /*
428 =============================
429 idGameBustOutWindow::WriteToSaveGame
430 =============================
431 */
433  idWindow::WriteToSaveGame( savefile );
434 
435  gamerunning.WriteToSaveGame( savefile );
436  onFire.WriteToSaveGame( savefile );
437  onContinue.WriteToSaveGame( savefile );
438  onNewGame.WriteToSaveGame( savefile );
439  onNewLevel.WriteToSaveGame( savefile );
440 
441  savefile->Write( &timeSlice, sizeof(timeSlice) );
442  savefile->Write( &gameOver, sizeof(gameOver) );
443  savefile->Write( &numLevels, sizeof(numLevels) );
444 
445  // Board Data is loaded when GUI is loaded, don't need to save
446 
447  savefile->Write( &numBricks, sizeof(numBricks) );
448  savefile->Write( &currentLevel, sizeof(currentLevel) );
449 
450  savefile->Write( &updateScore, sizeof(updateScore) );
451  savefile->Write( &gameScore, sizeof(gameScore) );
452  savefile->Write( &nextBallScore, sizeof(nextBallScore) );
453 
454  savefile->Write( &bigPaddleTime, sizeof(bigPaddleTime) );
455  savefile->Write( &paddleVelocity, sizeof(paddleVelocity) );
456 
457  savefile->Write( &ballSpeed, sizeof(ballSpeed) );
458  savefile->Write( &ballsRemaining, sizeof(ballsRemaining) );
459  savefile->Write( &ballsInPlay, sizeof(ballsInPlay) );
460  savefile->Write( &ballHitCeiling, sizeof(ballHitCeiling) );
461 
462  // Write Entities
463  int i;
464  int numberOfEnts = entities.Num();
465  savefile->Write( &numberOfEnts, sizeof(numberOfEnts) );
466  for ( i=0; i<numberOfEnts; i++ ) {
467  entities[i]->WriteToSaveGame( savefile );
468  }
469 
470  // Write Balls
471  numberOfEnts = balls.Num();
472  savefile->Write( &numberOfEnts, sizeof(numberOfEnts) );
473  for ( i=0; i<numberOfEnts; i++ ) {
474  int ballIndex = entities.FindIndex( balls[i] );
475  savefile->Write( &ballIndex, sizeof(ballIndex) );
476  }
477 
478  // Write Powerups
479  numberOfEnts = powerUps.Num();
480  savefile->Write( &numberOfEnts, sizeof(numberOfEnts) );
481  for ( i=0; i<numberOfEnts; i++ ) {
482  int powerIndex = entities.FindIndex( powerUps[i] );
483  savefile->Write( &powerIndex, sizeof(powerIndex) );
484  }
485 
486  // Write paddle
487  paddle->WriteToSaveGame( savefile );
488 
489  // Write Bricks
490  int row;
491  for ( row=0; row<BOARD_ROWS; row++ ) {
492  numberOfEnts = board[row].Num();
493  savefile->Write( &numberOfEnts, sizeof(numberOfEnts) );
494  for ( i=0; i<numberOfEnts; i++ ) {
495  board[row][i]->WriteToSaveGame( savefile );
496  }
497  }
498 }
499 
500 /*
501 =============================
502 idGameBustOutWindow::ReadFromSaveGame
503 =============================
504 */
506  idWindow::ReadFromSaveGame( savefile );
507 
508  // Clear out existing paddle and entities from GUI load
509  delete paddle;
510  entities.DeleteContents( true );
511 
512  gamerunning.ReadFromSaveGame( savefile );
513  onFire.ReadFromSaveGame( savefile );
514  onContinue.ReadFromSaveGame( savefile );
515  onNewGame.ReadFromSaveGame( savefile );
516  onNewLevel.ReadFromSaveGame( savefile );
517 
518  savefile->Read( &timeSlice, sizeof(timeSlice) );
519  savefile->Read( &gameOver, sizeof(gameOver) );
520  savefile->Read( &numLevels, sizeof(numLevels) );
521 
522  // Board Data is loaded when GUI is loaded, don't need to save
523 
524  savefile->Read( &numBricks, sizeof(numBricks) );
525  savefile->Read( &currentLevel, sizeof(currentLevel) );
526 
527  savefile->Read( &updateScore, sizeof(updateScore) );
528  savefile->Read( &gameScore, sizeof(gameScore) );
529  savefile->Read( &nextBallScore, sizeof(nextBallScore) );
530 
531  savefile->Read( &bigPaddleTime, sizeof(bigPaddleTime) );
532  savefile->Read( &paddleVelocity, sizeof(paddleVelocity) );
533 
534  savefile->Read( &ballSpeed, sizeof(ballSpeed) );
535  savefile->Read( &ballsRemaining, sizeof(ballsRemaining) );
536  savefile->Read( &ballsInPlay, sizeof(ballsInPlay) );
537  savefile->Read( &ballHitCeiling, sizeof(ballHitCeiling) );
538 
539  int i;
540  int numberOfEnts;
541 
542  // Read entities
543  savefile->Read( &numberOfEnts, sizeof(numberOfEnts) );
544  for ( i=0; i<numberOfEnts; i++ ) {
545  BOEntity *ent;
546 
547  ent = new BOEntity( this );
548  ent->ReadFromSaveGame( savefile, this );
549  entities.Append( ent );
550  }
551 
552  // Read balls
553  savefile->Read( &numberOfEnts, sizeof(numberOfEnts) );
554  for ( i=0; i<numberOfEnts; i++ ) {
555  int ballIndex;
556  savefile->Read( &ballIndex, sizeof(ballIndex) );
557  balls.Append( entities[ballIndex] );
558  }
559 
560  // Read powerups
561  savefile->Read( &numberOfEnts, sizeof(numberOfEnts) );
562  for ( i=0; i<numberOfEnts; i++ ) {
563  int powerIndex;
564  savefile->Read( &powerIndex, sizeof(powerIndex) );
565  balls.Append( entities[powerIndex] );
566  }
567 
568  // Read paddle
569  paddle = new BOBrick();
570  paddle->ReadFromSaveGame( savefile, this );
571 
572  // Read board
573  int row;
574  for ( row=0; row<BOARD_ROWS; row++ ) {
575  savefile->Read( &numberOfEnts, sizeof(numberOfEnts) );
576  for ( i=0; i<numberOfEnts; i++ ) {
577  BOBrick *brick = new BOBrick();
578  brick->ReadFromSaveGame( savefile, this );
579  board[row].Append( brick );
580  }
581  }
582 }
583 
584 /*
585 =============================
586 idGameBustOutWindow::ResetGameState
587 =============================
588 */
590  gamerunning = false;
591  gameOver = false;
592  onFire = false;
593  onContinue = false;
594  onNewGame = false;
595  onNewLevel = false;
596 
597  // Game moves forward 16 milliseconds every frame
598  timeSlice = 0.016f;
599  ballsRemaining = 3;
601  ballsInPlay = 0;
602  updateScore = false;
603  numBricks = 0;
604  currentLevel = 1;
605  gameScore = 0;
606  bigPaddleTime = 0;
607  nextBallScore = gameScore + 10000;
608 
609  ClearBoard();
610 }
611 
612 /*
613 =============================
614 idGameBustOutWindow::CommonInit
615 =============================
616 */
618  BOEntity *ent;
619 
620  // Precache images
621  declManager->FindMaterial( "game/bustout/ball" );
622  declManager->FindMaterial( "game/bustout/doublepaddle" );
623  declManager->FindMaterial( "game/bustout/powerup_bigpaddle" );
624  declManager->FindMaterial( "game/bustout/powerup_multiball" );
625  declManager->FindMaterial( "game/bustout/brick" );
626 
627  // Precache sounds
628  declManager->FindSound( "arcade_ballbounce" );
629  declManager->FindSound( "arcade_brickhit" );
630  declManager->FindSound( "arcade_missedball" );
631  declManager->FindSound( "arcade_sadsound" );
632  declManager->FindSound( "arcade_extraball" );
633  declManager->FindSound( "arcade_powerup" );
634 
635  ResetGameState();
636 
637  numLevels = 0;
638  boardDataLoaded = false;
640 
641  // Create Paddle
642  ent = new BOEntity( this );
643  paddle = new BOBrick( ent, 260.f, 440.f, 96.f, 24.f );
644  paddle->ent->SetMaterial( "game/bustout/paddle" );
645 }
646 
647 /*
648 =============================
649 idGameBustOutWindow::HandleEvent
650 =============================
651 */
652 const char *idGameBustOutWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
653  int key = event->evValue;
654 
655  // need to call this to allow proper focus and capturing on embedded children
656  const char *ret = idWindow::HandleEvent(event, updateVisuals);
657 
658  if ( event->evType == SE_KEY ) {
659 
660  if ( !event->evValue2 ) {
661  return ret;
662  }
663  if ( key == K_MOUSE1) {
664  // Mouse was clicked
665  if ( ballsInPlay == 0 ) {
666  BOEntity *ball = CreateNewBall();
667 
668  ball->SetVisible( true );
669  ball->position.x = paddle->ent->position.x + 48.f;
670  ball->position.y = 430.f;
671 
672  ball->velocity.x = ballSpeed;
673  ball->velocity.y = -ballSpeed*2.f;
674  ball->velocity.NormalizeFast();
675  ball->velocity *= ballSpeed;
676  }
677  } else {
678  return ret;
679  }
680  }
681 
682  return ret;
683 }
684 
685 /*
686 =============================
687 idGameBustOutWindow::ParseInternalVar
688 =============================
689 */
691  if ( idStr::Icmp(_name, "gamerunning") == 0 ) {
692  gamerunning = src->ParseBool();
693  return true;
694  }
695  if ( idStr::Icmp(_name, "onFire") == 0 ) {
696  onFire = src->ParseBool();
697  return true;
698  }
699  if ( idStr::Icmp(_name, "onContinue") == 0 ) {
700  onContinue = src->ParseBool();
701  return true;
702  }
703  if ( idStr::Icmp(_name, "onNewGame") == 0 ) {
704  onNewGame = src->ParseBool();
705  return true;
706  }
707  if ( idStr::Icmp(_name, "onNewLevel") == 0 ) {
708  onNewLevel = src->ParseBool();
709  return true;
710  }
711  if ( idStr::Icmp(_name, "numLevels") == 0 ) {
712  numLevels = src->ParseInt();
713 
714  // Load all the level images
715  LoadBoardFiles();
716  return true;
717  }
718 
719  return idWindow::ParseInternalVar(_name, src);
720 }
721 
722 /*
723 =============================
724 idGameBustOutWindow::GetWinVarByName
725 =============================
726 */
727 idWinVar *idGameBustOutWindow::GetWinVarByName(const char *_name, bool winLookup, drawWin_t** owner) {
728  idWinVar *retVar = NULL;
729 
730  if ( idStr::Icmp(_name, "gamerunning") == 0 ) {
731  retVar = &gamerunning;
732  } else if ( idStr::Icmp(_name, "onFire") == 0 ) {
733  retVar = &onFire;
734  } else if ( idStr::Icmp(_name, "onContinue") == 0 ) {
735  retVar = &onContinue;
736  } else if ( idStr::Icmp(_name, "onNewGame") == 0 ) {
737  retVar = &onNewGame;
738  } else if ( idStr::Icmp(_name, "onNewLevel") == 0 ) {
739  retVar = &onNewLevel;
740  }
741 
742  if(retVar) {
743  return retVar;
744  }
745 
746  return idWindow::GetWinVarByName(_name, winLookup, owner);
747 }
748 
749 /*
750 =============================
751 idGameBustOutWindow::PostParse
752 =============================
753 */
756 }
757 
758 /*
759 =============================
760 idGameBustOutWindow::Draw
761 =============================
762 */
763 void idGameBustOutWindow::Draw(int time, float x, float y) {
764  int i;
765 
766  //Update the game every frame before drawing
767  UpdateGame();
768 
769  for( i = entities.Num()-1; i >= 0; i-- ) {
770  entities[i]->Draw(dc);
771  }
772 }
773 
774 /*
775 =============================
776 idGameBustOutWindow::Activate
777 =============================
778 */
779 const char *idGameBustOutWindow::Activate(bool activate) {
780  return "";
781 }
782 
783 
784 /*
785 =============================
786 idGameBustOutWindow::UpdateScore
787 =============================
788 */
790 
791  if ( gameOver ) {
792  gui->HandleNamedEvent( "GameOver" );
793  return;
794  }
795 
796  // Check for level progression
797  if ( numBricks == 0 ) {
798  ClearBalls();
799 
800  gui->HandleNamedEvent( "levelComplete" );
801  }
802 
803  // Check for new ball score
804  if ( gameScore >= nextBallScore ) {
805  ballsRemaining++;
806  gui->HandleNamedEvent( "extraBall" );
807 
808  // Play sound
809  session->sw->PlayShaderDirectly( "arcade_extraball", S_UNIQUE_CHANNEL );
810 
811  nextBallScore = gameScore + 10000;
812  }
813 
814  gui->SetStateString( "player_score", va("%i", gameScore ) );
815  gui->SetStateString( "balls_remaining", va("%i", ballsRemaining ) );
816  gui->SetStateString( "current_level", va("%i", currentLevel ) );
817  gui->SetStateString( "next_ball_score", va("%i", nextBallScore ) );
818 }
819 
820 /*
821 =============================
822 idGameBustOutWindow::ClearBoard
823 =============================
824 */
826  int i,j;
827 
828  ClearPowerups();
829 
830  ballHitCeiling = false;
831 
832  for ( i=0; i<BOARD_ROWS; i++ ) {
833  for ( j=0; j<board[i].Num(); j++ ) {
834 
835  BOBrick *brick = board[i][j];
836  brick->ent->removed = true;
837  }
838 
839  board[i].DeleteContents( true );
840  }
841 }
842 
843 /*
844 =============================
845 idGameBustOutWindow::ClearPowerups
846 =============================
847 */
849  while ( powerUps.Num() ) {
850  powerUps[0]->removed = true;
851  powerUps.RemoveIndex( 0 );
852  }
853 }
854 
855 /*
856 =============================
857 idGameBustOutWindow::ClearBalls
858 =============================
859 */
861  while ( balls.Num() ) {
862  balls[0]->removed = true;
863  balls.RemoveIndex( 0 );
864  }
865 
866  ballsInPlay = 0;
867 }
868 
869 /*
870 =============================
871 idGameBustOutWindow::LoadBoardFiles
872 =============================
873 */
875  int i;
876  int w,h;
877  ID_TIME_T time;
878  int boardSize;
879  byte *currentBoard;
880 
881  if ( boardDataLoaded ) {
882  return;
883  }
884 
885  boardSize = 9 * 12 * 4;
886  levelBoardData = (byte*)Mem_Alloc( boardSize * numLevels );
887 
888  currentBoard = levelBoardData;
889 
890  for ( i=0; i<numLevels; i++ ) {
891  byte *pic;
892  idStr name = "guis/assets/bustout/level";
893  name += (i+1);
894  name += ".tga";
895 
896  R_LoadImage( name, &pic, &w, &h, &time, false );
897 
898  if ( pic != NULL ) {
899  if ( w != 9 || h != 12 ) {
900  common->DWarning( "Hell Bust-Out level image not correct dimensions! (%d x %d)", w, h );
901  }
902 
903  memcpy( currentBoard, pic, boardSize );
904  Mem_Free(pic);
905  }
906 
907  currentBoard += boardSize;
908  }
909 
910  boardDataLoaded = true;
911 }
912 
913 /*
914 =============================
915 idGameBustOutWindow::SetCurrentBoard
916 =============================
917 */
919  int i,j;
920  int realLevel = ((currentLevel-1) % numLevels);
921  int boardSize;
922  byte *currentBoard;
923  float bx = 11.f;
924  float by = 24.f;
925  float stepx = 619.f / 9.f;
926  float stepy = ( 256 / 12.f );
927 
928  boardSize = 9 * 12 * 4;
929  currentBoard = levelBoardData + ( realLevel * boardSize );
930 
931  for ( j=0; j<BOARD_ROWS; j++ ) {
932  bx = 11.f;
933 
934  for ( i=0; i<9; i++ ) {
935  int pixelindex = (j*9*4) + (i*4);
936 
937  if ( currentBoard[pixelindex + 3] ) {
938  idVec4 bcolor;
939  float pType = 0.f;
940 
941  BOEntity *bent = new BOEntity( this );
942  BOBrick *brick = new BOBrick( bent, bx, by, stepx, stepy );
943 
944  bcolor.x = currentBoard[pixelindex + 0] / 255.f;
945  bcolor.y = currentBoard[pixelindex + 1] / 255.f;
946  bcolor.z = currentBoard[pixelindex + 2] / 255.f;
947  bcolor.w = 1.f;
948  brick->SetColor( bcolor );
949 
950  pType = currentBoard[pixelindex + 3] / 255.f;
951  if ( pType > 0.f && pType < 1.f ) {
952  if ( pType < 0.5f ) {
953  brick->powerup = POWERUP_BIGPADDLE;
954  } else {
955  brick->powerup = POWERUP_MULTIBALL;
956  }
957  }
958 
959  board[j].Append( brick );
960  numBricks++;
961  }
962 
963  bx += stepx;
964  }
965 
966  by += stepy;
967  }
968 }
969 
970 /*
971 =============================
972 idGameBustOutWindow::CreateNewBall
973 =============================
974 */
976  BOEntity *ball;
977 
978  ball = new BOEntity( this );
979  ball->position.x = 300.f;
980  ball->position.y = 416.f;
981  ball->SetMaterial( "game/bustout/ball" );
982  ball->SetSize( BALL_RADIUS*2.f, BALL_RADIUS*2.f );
983  ball->SetVisible( false );
984 
985  ballsInPlay++;
986 
987  balls.Append( ball );
988  entities.Append( ball );
989 
990  return ball;
991 }
992 
993 /*
994 =============================
995 idGameBustOutWindow::CreatePowerup
996 =============================
997 */
999  BOEntity *powerEnt = new BOEntity( this );
1000 
1001  powerEnt->position.x = brick->x;
1002  powerEnt->position.y = brick->y;
1003  powerEnt->velocity.x = 0.f;
1004  powerEnt->velocity.y = 64.f;
1005 
1006  powerEnt->powerup = brick->powerup;
1007 
1008  switch( powerEnt->powerup ) {
1009  case POWERUP_BIGPADDLE:
1010  powerEnt->SetMaterial( "game/bustout/powerup_bigpaddle" );
1011  break;
1012  case POWERUP_MULTIBALL:
1013  powerEnt->SetMaterial( "game/bustout/powerup_multiball" );
1014  break;
1015  default:
1016  powerEnt->SetMaterial( "textures/common/nodraw" );
1017  break;
1018  }
1019 
1020  powerEnt->SetSize( 619/9, 256/12 );
1021  powerEnt->SetVisible( true );
1022 
1023  powerUps.Append( powerEnt );
1024  entities.Append( powerEnt );
1025 
1026  return powerEnt;
1027 }
1028 
1029 /*
1030 =============================
1031 idGameBustOutWindow::UpdatePowerups
1032 =============================
1033 */
1035  idVec2 pos;
1036 
1037  for ( int i=0; i < powerUps.Num(); i++ ) {
1038  BOEntity *pUp = powerUps[i];
1039 
1040  // Check for powerup falling below screen
1041  if ( pUp->position.y > 480 ) {
1042 
1043  powerUps.RemoveIndex( i );
1044  pUp->removed = true;
1045  continue;
1046  }
1047 
1048  // Check for the paddle catching a powerup
1049  pos.x = pUp->position.x + ( pUp->width / 2 );
1050  pos.y = pUp->position.y + ( pUp->height / 2 );
1051 
1052  collideDir_t collision = paddle->checkCollision( pos, pUp->velocity );
1053  if ( collision != COLLIDE_NONE ) {
1054  BOEntity *ball;
1055 
1056  // Give the powerup to the player
1057  switch( pUp->powerup ) {
1058  case POWERUP_BIGPADDLE:
1059  bigPaddleTime = gui->GetTime() + 15000;
1060  break;
1061  case POWERUP_MULTIBALL:
1062  // Create 2 new balls in the spot of the existing ball
1063  for ( int b=0; b<2; b++ ) {
1064  ball = CreateNewBall();
1065  ball->position = balls[0]->position;
1066  ball->velocity = balls[0]->velocity;
1067 
1068  if ( b == 0 ) {
1069  ball->velocity.x -= 35.f;
1070  } else {
1071  ball->velocity.x += 35.f;
1072  }
1073  ball->velocity.NormalizeFast();
1074  ball->velocity *= ballSpeed;
1075 
1076  ball->SetVisible( true );
1077  }
1078  break;
1079  default:
1080  break;
1081  }
1082 
1083  // Play the sound
1084  session->sw->PlayShaderDirectly( "arcade_powerup", S_UNIQUE_CHANNEL );
1085 
1086  // Remove it
1087  powerUps.RemoveIndex( i );
1088  pUp->removed = true;
1089  }
1090  }
1091 }
1092 
1093 /*
1094 =============================
1095 idGameBustOutWindow::UpdatePaddle
1096 =============================
1097 */
1099  idVec2 cursorPos;
1100  float oldPos = paddle->x;
1101 
1102  cursorPos.x = gui->CursorX();
1103  cursorPos.y = gui->CursorY();
1104 
1105  if ( bigPaddleTime > gui->GetTime() ) {
1106  paddle->x = cursorPos.x - 80.f;
1107  paddle->width = 160;
1108  paddle->ent->width = 160;
1109  paddle->ent->SetMaterial( "game/bustout/doublepaddle" );
1110  } else {
1111  paddle->x = cursorPos.x - 48.f;
1112  paddle->width = 96;
1113  paddle->ent->width = 96;
1114  paddle->ent->SetMaterial( "game/bustout/paddle" );
1115  }
1116  paddle->ent->position.x = paddle->x;
1117 
1118  paddleVelocity = (paddle->x - oldPos);
1119 }
1120 
1121 /*
1122 =============================
1123 idGameBustOutWindow::UpdateBall
1124 =============================
1125 */
1127  int ballnum,i,j;
1128  bool playSoundBounce = false;
1129  bool playSoundBrick = false;
1130  static int bounceChannel = 1;
1131 
1132  if ( ballsInPlay == 0 ) {
1133  return;
1134  }
1135 
1136  for ( ballnum = 0; ballnum < balls.Num(); ballnum++ ) {
1137  BOEntity *ball = balls[ballnum];
1138 
1139  // Check for ball going below screen, lost ball
1140  if ( ball->position.y > 480.f ) {
1141  ball->removed = true;
1142  continue;
1143  }
1144 
1145  // Check world collision
1146  if ( ball->position.y < 20 && ball->velocity.y < 0 ) {
1147  ball->velocity.y = -ball->velocity.y;
1148 
1149  // Increase ball speed when it hits ceiling
1150  if ( !ballHitCeiling ) {
1151  ballSpeed *= 1.25f;
1152  ballHitCeiling = true;
1153  }
1154  playSoundBounce = true;
1155  }
1156 
1157  if ( ball->position.x > 608 && ball->velocity.x > 0 ) {
1158  ball->velocity.x = -ball->velocity.x;
1159  playSoundBounce = true;
1160  } else if ( ball->position.x < 8 && ball->velocity.x < 0 ) {
1161  ball->velocity.x = -ball->velocity.x;
1162  playSoundBounce = true;
1163  }
1164 
1165  // Check for Paddle collision
1166  idVec2 ballCenter = ball->position + idVec2( BALL_RADIUS, BALL_RADIUS );
1167  collideDir_t collision = paddle->checkCollision( ballCenter, ball->velocity );
1168 
1169  if ( collision == COLLIDE_UP ) {
1170  if ( ball->velocity.y > 0 ) {
1171  idVec2 paddleVec( paddleVelocity*2, 0 );
1172  float centerX;
1173 
1174  if ( bigPaddleTime > gui->GetTime() ) {
1175  centerX = paddle->x + 80.f;
1176  } else {
1177  centerX = paddle->x + 48.f;
1178  }
1179 
1180  ball->velocity.y = -ball->velocity.y;
1181 
1182  paddleVec.x += (ball->position.x - centerX) * 2;
1183 
1184  ball->velocity += paddleVec;
1185  ball->velocity.NormalizeFast();
1186  ball->velocity *= ballSpeed;
1187 
1188  playSoundBounce = true;
1189  }
1190  } else if ( collision == COLLIDE_LEFT || collision == COLLIDE_RIGHT ) {
1191  if ( ball->velocity.y > 0 ) {
1192  ball->velocity.x = -ball->velocity.x;
1193  playSoundBounce = true;
1194  }
1195  }
1196 
1197  collision = COLLIDE_NONE;
1198 
1199  // Check for collision with bricks
1200  for ( i=0; i<BOARD_ROWS; i++ ) {
1201  int num = board[i].Num();
1202 
1203  for ( j=0; j<num; j++ ) {
1204  BOBrick *brick = (board[i])[j];
1205 
1206  collision = brick->checkCollision( ballCenter, ball->velocity );
1207  if ( collision ) {
1208  // Now break the brick if there was a collision
1209  brick->isBroken = true;
1210  brick->ent->fadeOut = true;
1211 
1212  if ( brick->powerup > POWERUP_NONE ) {
1213  BOEntity *pUp = CreatePowerup( brick );
1214  }
1215 
1216  numBricks--;
1217  gameScore += 100;
1218  updateScore = true;
1219 
1220  // Go ahead an forcibly remove the last brick, no fade
1221  if ( numBricks == 0 ) {
1222  brick->ent->removed = true;
1223  }
1224  board[i].Remove( brick );
1225  break;
1226  }
1227  }
1228 
1229  if ( collision ) {
1230  playSoundBrick = true;
1231  break;
1232  }
1233  }
1234 
1235  if ( collision == COLLIDE_DOWN || collision == COLLIDE_UP ) {
1236  ball->velocity.y *= -1;
1237  } else if ( collision == COLLIDE_LEFT || collision == COLLIDE_RIGHT ) {
1238  ball->velocity.x *= -1;
1239  }
1240 
1241  if ( playSoundBounce ) {
1242  session->sw->PlayShaderDirectly( "arcade_ballbounce", bounceChannel );
1243  } else if ( playSoundBrick ) {
1244  session->sw->PlayShaderDirectly( "arcade_brickhit", bounceChannel );
1245  }
1246 
1247  if ( playSoundBounce || playSoundBrick ) {
1248  bounceChannel++;
1249  if ( bounceChannel == 4 ) {
1250  bounceChannel = 1;
1251  }
1252  }
1253  }
1254 
1255  // Check to see if any balls were removed from play
1256  for ( ballnum=0; ballnum<balls.Num(); ballnum++ ) {
1257  if ( balls[ballnum]->removed ) {
1258  ballsInPlay--;
1259  balls.RemoveIndex( ballnum );
1260  }
1261  }
1262 
1263  // If all the balls were removed, update the game accordingly
1264  if ( ballsInPlay == 0 ) {
1265  if ( ballsRemaining == 0 ) {
1266  gameOver = true;
1267 
1268  // Game Over sound
1269  session->sw->PlayShaderDirectly( "arcade_sadsound", S_UNIQUE_CHANNEL );
1270  } else {
1271  ballsRemaining--;
1272 
1273  // Ball was lost, but game is not over
1274  session->sw->PlayShaderDirectly( "arcade_missedball", S_UNIQUE_CHANNEL );
1275  }
1276 
1277  ClearPowerups();
1278  updateScore = true;
1279  }
1280 }
1281 
1282 /*
1283 =============================
1284 idGameBustOutWindow::UpdateGame
1285 =============================
1286 */
1288  int i;
1289 
1290  if ( onNewGame ) {
1291  ResetGameState();
1292 
1293  // Create Board
1294  SetCurrentBoard();
1295 
1296  gamerunning = true;
1297  }
1298  if ( onContinue ) {
1299  gameOver = false;
1300  ballsRemaining = 3;
1301 
1302  onContinue = false;
1303  }
1304  if ( onNewLevel ) {
1305  currentLevel++;
1306 
1307  ClearBoard();
1308  SetCurrentBoard();
1309 
1310  ballSpeed = BALL_SPEED * ( 1.f + ((float)currentLevel/5.f) );
1311  if ( ballSpeed > BALL_MAXSPEED ) {
1313  }
1314  updateScore = true;
1315  onNewLevel = false;
1316  }
1317 
1318  if(gamerunning == true) {
1319 
1320  UpdatePaddle();
1321  UpdateBall();
1322  UpdatePowerups();
1323 
1324  for( i = 0; i < entities.Num(); i++ ) {
1325  entities[i]->Update( timeSlice, gui->GetTime() );
1326  }
1327 
1328  // Delete entities that need to be deleted
1329  for( i = entities.Num()-1; i >= 0; i-- ) {
1330  if( entities[i]->removed ) {
1331  BOEntity* ent = entities[i];
1332  delete ent;
1333  entities.RemoveIndex(i);
1334  }
1335  }
1336 
1337  if ( updateScore ) {
1338  UpdateScore();
1339  updateScore = false;
1340  }
1341  }
1342 }
virtual void ReadFromSaveGame(idFile *savefile, idGameBustOutWindow *game)
GLubyte g
Definition: glext.h:4662
virtual void SetStateString(const char *varName, const char *value)
idList< BOBrick * > board[BOARD_ROWS]
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
virtual const char * Activate(bool activate)
idSoundWorld * sw
Definition: Session.h:154
idVec4 colorWhite
Definition: Lib.cpp:116
#define BOARD_ROWS
float y
Definition: Vector.h:811
virtual void WriteToSaveGame(idFile *savefile)
float y
Definition: Vector.h:55
virtual bool ParseInternalVar(const char *name, idParser *src)
Definition: Window.cpp:1915
virtual void Draw(int time, float x, float y)
virtual ~BOEntity()
virtual void PlayShaderDirectly(const char *name, int channel=-1)=0
GLenum GLint GLint y
Definition: glext.h:2849
float z
Definition: Vector.h:812
virtual void ReadFromSaveGame(idFile *savefile)
void R_LoadImage(const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp, bool makePowerOf2)
virtual bool ParseInternalVar(const char *name, idParser *src)
float NormalizeFast(void)
Definition: Vector.h:180
void SetVisible(bool isVisible)
case const float
Definition: Callbacks.cpp:62
virtual void WriteToSaveGame(idFile *savefile)
Definition: Window.cpp:3464
collideDir_t
idDeviceContext * dc
Definition: Window.h:425
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
GLuint src
Definition: glext.h:5390
idList< BOEntity * > balls
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
GLuint GLuint num
Definition: glext.h:5390
Boolean result
int Icmp(const char *text) const
Definition: Str.h:667
virtual void WriteToSaveGame(idFile *savefile)
Definition: Winvar.h:137
virtual void Draw(idDeviceContext *dc)
void Zero(void)
Definition: Vector.h:119
void SetColor(idVec4 bcolor)
void DrawMaterialRotated(float x, float y, float w, float h, const idMaterial *mat, const idVec4 &color, float scalex=1.0, float scaley=1.0, float angle=0.0f)
Definition: File.h:50
float LengthFast(void) const
Definition: Vector.h:159
virtual void WriteToSaveGame(idFile *savefile)
bool ParseBool(void)
Definition: Parser.cpp:2797
Definition: Vector.h:52
void SetMaterial(const char *name)
virtual void PostParse()
Definition: Window.cpp:1709
int ParseInt(void)
Definition: Parser.cpp:2775
GLuint index
Definition: glext.h:3476
#define BALL_SPEED
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
Definition: Vector.h:808
static float Fabs(float f)
Definition: Math.h:779
virtual void virtual void virtual void DWarning(const char *fmt,...) id_attribute((format(printf
idCommon * common
Definition: Common.cpp:206
#define NULL
Definition: Lib.h:88
int evValue2
Definition: sys_public.h:218
virtual void WriteToSaveGame(idFile *savefile)
virtual float CursorY()
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
powerupType_t powerup
float w
Definition: Vector.h:813
float x
Definition: Vector.h:54
virtual void ReadFromSaveGame(idFile *savefile, idGameBustOutWindow *_game)
void DeleteContents(bool clear)
Definition: List.h:207
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
idList< BOEntity * > powerUps
virtual void ReadFromSaveGame(idFile *savefile)
Definition: Winvar.h:141
GLenum GLsizei width
Definition: glext.h:2846
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
#define DEG2RAD(a)
Definition: Math.h:56
void ReadSaveGameString(idStr &string, idFile *savefile)
Definition: Window.cpp:3590
void WriteSaveGameString(const char *string, idFile *savefile)
Definition: Window.cpp:3404
sysEventType_t evType
Definition: sys_public.h:216
GLenum GLsizei GLsizei height
Definition: glext.h:2856
idList< BOEntity * > entities
idDeclManager * declManager
const idMaterial * material
GLubyte GLubyte b
Definition: glext.h:4662
collideDir_t checkCollision(idVec2 pos, idVec2 vel)
void SetColor(float r, float g, float b, float a)
idGameBustOutWindow * game
int Append(const type &obj)
Definition: List.h:646
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
powerupType_t powerup
#define BALL_RADIUS
GLenum GLenum GLvoid * row
Definition: glext.h:2866
idUserInterfaceLocal * gui
Definition: Window.h:427
void SetSize(float _width, float _height)
tuple f
Definition: idal.py:89
int Num(void) const
Definition: List.h:265
bool RemoveIndex(int index)
Definition: List.h:849
unsigned char byte
Definition: Lib.h:75
const GLcharARB * name
Definition: glext.h:3629
virtual int Write(const void *buffer, int len)
Definition: File.cpp:189
Definition: Str.h:116
GLbyte by
Definition: glext.h:4538
#define S_UNIQUE_CHANNEL
#define BALL_MAXSPEED
idGameBustOutWindow(idUserInterfaceLocal *gui)
void SetSort(float s) const
Definition: Material.h:513
BOEntity(idGameBustOutWindow *_game)
int FindIndex(const type &obj) const
Definition: List.h:761
BOEntity * ent
idGame * game
Definition: Game_local.cpp:65
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
virtual idWinVar * GetWinVarByName(const char *_name, bool winLookup=false, drawWin_t **owner=NULL)
BOEntity * CreatePowerup(BOBrick *brick)
idSession * session
Definition: Session.cpp:48
char * va(const char *fmt,...)
Definition: Str.cpp:1568
idStr materialName
virtual const char * HandleEvent(const sysEvent_t *event, bool *updateVisuals)
Definition: Window.cpp:709
virtual void HandleNamedEvent(const char *namedEvent)
float x
Definition: Vector.h:810
idVec2 position
virtual void Update(float timeslice, int guiTime)
virtual float CursorX()
virtual idWinVar * GetWinVarByName(const char *_name, bool winLookup=false, drawWin_t **owner=NULL)
Definition: Window.cpp:1776
idVec2 velocity
bool Remove(const type &obj)
Definition: List.h:878
virtual void ReadFromSaveGame(idFile *savefile)
Definition: Window.cpp:3607
virtual const char * HandleEvent(const sysEvent_t *event, bool *updateVisuals)