GameSSDWindow.cpp (61761B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop 29 #include "../idlib/precompiled.h" 30 31 #include "DeviceContext.h" 32 #include "Window.h" 33 #include "UserInterfaceLocal.h" 34 #include "GameSSDWindow.h" 35 36 37 #define Z_NEAR 100.0f 38 #define Z_FAR 4000.0f 39 #define ENTITY_START_DIST 3000 40 41 #define V_WIDTH 640.0f 42 #define V_HEIGHT 480.0f 43 44 /* 45 ***************************************************************************** 46 * SSDCrossHair 47 **************************************************************************** 48 */ 49 50 #define CROSSHAIR_STANDARD_MATERIAL "game/SSD/crosshair_standard" 51 #define CROSSHAIR_SUPER_MATERIAL "game/SSD/crosshair_super" 52 53 SSDCrossHair::SSDCrossHair() { 54 } 55 56 SSDCrossHair::~SSDCrossHair() { 57 } 58 59 void SSDCrossHair::WriteToSaveGame( idFile *savefile ) { 60 61 savefile->Write(¤tCrosshair, sizeof(currentCrosshair)); 62 savefile->Write(&crosshairWidth, sizeof(crosshairWidth)); 63 savefile->Write(&crosshairHeight, sizeof(crosshairHeight)); 64 65 } 66 67 void SSDCrossHair::ReadFromSaveGame( idFile *savefile ) { 68 69 InitCrosshairs(); 70 71 savefile->Read(¤tCrosshair, sizeof(currentCrosshair)); 72 savefile->Read(&crosshairWidth, sizeof(crosshairWidth)); 73 savefile->Read(&crosshairHeight, sizeof(crosshairHeight)); 74 75 } 76 77 void SSDCrossHair::InitCrosshairs() { 78 79 crosshairMaterial[CROSSHAIR_STANDARD] = declManager->FindMaterial( CROSSHAIR_STANDARD_MATERIAL ); 80 crosshairMaterial[CROSSHAIR_SUPER] = declManager->FindMaterial( CROSSHAIR_SUPER_MATERIAL ); 81 82 crosshairWidth = 64; 83 crosshairHeight = 64; 84 85 currentCrosshair = CROSSHAIR_STANDARD; 86 87 } 88 89 void SSDCrossHair::Draw(const idVec2& cursor) { 90 91 float x,y; 92 x = cursor.x-(crosshairWidth/2); 93 y = cursor.y-(crosshairHeight/2); 94 dc->DrawMaterial(x, y, crosshairWidth, crosshairHeight, crosshairMaterial[currentCrosshair], colorWhite, 1.0f, 1.0f); 95 96 } 97 98 /* 99 ***************************************************************************** 100 * SSDEntity 101 **************************************************************************** 102 */ 103 104 SSDEntity::SSDEntity() { 105 EntityInit(); 106 } 107 108 SSDEntity::~SSDEntity() { 109 } 110 111 void SSDEntity::WriteToSaveGame( idFile *savefile ) { 112 113 savefile->Write(&type, sizeof(type)); 114 game->WriteSaveGameString(materialName, savefile); 115 savefile->Write(&position, sizeof(position)); 116 savefile->Write(&size, sizeof(size)); 117 savefile->Write(&radius, sizeof(radius)); 118 savefile->Write(&hitRadius, sizeof(hitRadius)); 119 savefile->Write(&rotation, sizeof(rotation)); 120 121 savefile->Write(&matColor, sizeof(matColor)); 122 123 game->WriteSaveGameString(text, savefile); 124 savefile->Write(&textScale, sizeof(textScale)); 125 savefile->Write(&foreColor, sizeof(foreColor)); 126 127 savefile->Write(¤tTime, sizeof(currentTime)); 128 savefile->Write(&lastUpdate, sizeof(lastUpdate)); 129 savefile->Write(&elapsed, sizeof(elapsed)); 130 131 savefile->Write(&destroyed, sizeof(destroyed)); 132 savefile->Write(&noHit, sizeof(noHit)); 133 savefile->Write(&noPlayerDamage, sizeof(noPlayerDamage)); 134 135 savefile->Write(&inUse, sizeof(inUse)); 136 137 } 138 139 void SSDEntity::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 140 141 savefile->Read(&type, sizeof(type)); 142 game->ReadSaveGameString(materialName, savefile); 143 SetMaterial(materialName); 144 savefile->Read(&position, sizeof(position)); 145 savefile->Read(&size, sizeof(size)); 146 savefile->Read(&radius, sizeof(radius)); 147 savefile->Read(&hitRadius, sizeof(hitRadius)); 148 savefile->Read(&rotation, sizeof(rotation)); 149 150 savefile->Read(&matColor, sizeof(matColor)); 151 152 game->ReadSaveGameString(text, savefile); 153 savefile->Read(&textScale, sizeof(textScale)); 154 savefile->Read(&foreColor, sizeof(foreColor)); 155 156 game = _game; 157 savefile->Read(¤tTime, sizeof(currentTime)); 158 savefile->Read(&lastUpdate, sizeof(lastUpdate)); 159 savefile->Read(&elapsed, sizeof(elapsed)); 160 161 savefile->Read(&destroyed, sizeof(destroyed)); 162 savefile->Read(&noHit, sizeof(noHit)); 163 savefile->Read(&noPlayerDamage, sizeof(noPlayerDamage)); 164 165 savefile->Read(&inUse, sizeof(inUse)); 166 } 167 168 void SSDEntity::EntityInit() { 169 170 inUse = false; 171 172 173 type = SSD_ENTITY_BASE; 174 175 materialName = ""; 176 material = NULL; 177 position.Zero(); 178 size.Zero(); 179 radius = 0.0f; 180 hitRadius = 0.0f; 181 rotation = 0.0f; 182 183 184 currentTime = 0; 185 lastUpdate = 0; 186 187 destroyed = false; 188 noHit = false; 189 noPlayerDamage = false; 190 191 matColor.Set(1, 1, 1, 1); 192 193 text = ""; 194 textScale = 1.0f; 195 foreColor.Set(1, 1, 1, 1); 196 } 197 198 void SSDEntity::SetGame(idGameSSDWindow* _game) { 199 game = _game; 200 } 201 202 void SSDEntity::SetMaterial(const char* name) { 203 materialName = name; 204 material = declManager->FindMaterial( name ); 205 material->SetSort( SS_GUI ); 206 } 207 208 void SSDEntity::SetPosition(const idVec3& _position) { 209 position = _position; 210 } 211 212 void SSDEntity::SetSize(const idVec2& _size) { 213 size = _size; 214 } 215 216 void SSDEntity::SetRadius(float _radius, float _hitFactor) { 217 radius = _radius; 218 hitRadius = _radius*_hitFactor; 219 } 220 221 void SSDEntity::SetRotation(float _rotation) { 222 rotation = _rotation; 223 } 224 225 void SSDEntity::Update() { 226 227 currentTime = game->ssdTime; 228 229 //Is this the first update 230 if(lastUpdate == 0) { 231 lastUpdate = currentTime; 232 return; 233 } 234 235 elapsed = currentTime - lastUpdate; 236 237 EntityUpdate(); 238 239 lastUpdate = currentTime; 240 } 241 242 bool SSDEntity::HitTest(const idVec2& pt) { 243 244 if(noHit) { 245 return false; 246 } 247 248 idVec3 screenPos = WorldToScreen(position); 249 250 251 //Scale the radius based on the distance from the player 252 float scale = 1.0f -((screenPos.z-Z_NEAR)/(Z_FAR-Z_NEAR)); 253 float scaledRad = scale*hitRadius; 254 255 //So we can compare against the square of the length between two points 256 float scaleRadSqr = scaledRad*scaledRad; 257 258 idVec2 diff = screenPos.ToVec2()-pt; 259 float dist = idMath::Fabs(diff.LengthSqr()); 260 261 if(dist < scaleRadSqr) { 262 return true; 263 } 264 return false; 265 } 266 267 void SSDEntity::Draw() { 268 269 270 idVec2 persize; 271 float x,y; 272 273 idBounds bounds; 274 bounds[0] = idVec3(position.x - (size.x/2.0f), position.y - (size.y/2.0f), position.z); 275 bounds[1] = idVec3(position.x + (size.x/2.0f), position.y + (size.y/2.0f), position.z); 276 277 idBounds screenBounds = WorldToScreen(bounds); 278 persize.x = idMath::Fabs(screenBounds[1].x - screenBounds[0].x); 279 persize.y = idMath::Fabs(screenBounds[1].y - screenBounds[0].y); 280 281 idVec3 center = screenBounds.GetCenter(); 282 283 x = screenBounds[0].x; 284 y = screenBounds[1].y; 285 dc->DrawMaterialRotated(x, y, persize.x, persize.y, material, matColor, 1.0f, 1.0f, DEG2RAD(rotation)); 286 287 if(text.Length() > 0) { 288 idRectangle rect( x, y, VIRTUAL_WIDTH, VIRTUAL_HEIGHT ); 289 dc->DrawText( text, textScale, 0, foreColor, rect, false ); 290 } 291 292 } 293 294 void SSDEntity::DestroyEntity() { 295 inUse = false; 296 } 297 298 idBounds SSDEntity::WorldToScreen(const idBounds worldBounds) { 299 300 idVec3 screenMin = WorldToScreen(worldBounds[0]); 301 idVec3 screenMax = WorldToScreen(worldBounds[1]); 302 303 idBounds screenBounds(screenMin, screenMax); 304 return screenBounds; 305 } 306 307 idVec3 SSDEntity::WorldToScreen(const idVec3& worldPos) { 308 309 float d = 0.5f*V_WIDTH*idMath::Tan(DEG2RAD(90.0f)/2.0f); 310 311 //World To Camera Coordinates 312 idVec3 cameraTrans(0,0,d); 313 idVec3 cameraPos; 314 cameraPos = worldPos + cameraTrans; 315 316 //Camera To Screen Coordinates 317 idVec3 screenPos; 318 screenPos.x = d*cameraPos.x/cameraPos.z + (0.5f*V_WIDTH-0.5f); 319 screenPos.y = -d*cameraPos.y/cameraPos.z + (0.5f*V_HEIGHT-0.5f); 320 screenPos.z = cameraPos.z; 321 322 return screenPos; 323 } 324 325 idVec3 SSDEntity::ScreenToWorld(const idVec3& screenPos) { 326 327 idVec3 worldPos; 328 329 worldPos.x = screenPos.x - 0.5f * V_WIDTH; 330 worldPos.y = -(screenPos.y - 0.5f * V_HEIGHT); 331 worldPos.z = screenPos.z; 332 333 return worldPos; 334 } 335 336 /* 337 ***************************************************************************** 338 * SSDMover 339 **************************************************************************** 340 */ 341 342 SSDMover::SSDMover() { 343 } 344 345 SSDMover::~SSDMover() { 346 } 347 348 void SSDMover::WriteToSaveGame( idFile *savefile ) { 349 SSDEntity::WriteToSaveGame(savefile); 350 351 savefile->Write(&speed, sizeof(speed)); 352 savefile->Write(&rotationSpeed, sizeof(rotationSpeed)); 353 } 354 355 void SSDMover::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 356 SSDEntity::ReadFromSaveGame(savefile, _game); 357 358 savefile->Read(&speed, sizeof(speed)); 359 savefile->Read(&rotationSpeed, sizeof(rotationSpeed)); 360 } 361 362 void SSDMover::MoverInit(const idVec3& _speed, float _rotationSpeed) { 363 364 speed = _speed; 365 rotationSpeed = _rotationSpeed; 366 } 367 368 void SSDMover::EntityUpdate() { 369 370 SSDEntity::EntityUpdate(); 371 372 //Move forward based on speed (units per second) 373 idVec3 moved = ((float)elapsed/1000.0f)*speed; 374 position += moved; 375 376 float rotated = ((float)elapsed/1000.0f)*rotationSpeed*360.0f; 377 rotation += rotated; 378 if(rotation >= 360) { 379 rotation -= 360.0f; 380 } 381 if(rotation < 0) { 382 rotation += 360.0f; 383 } 384 } 385 386 387 /* 388 ***************************************************************************** 389 * SSDAsteroid 390 **************************************************************************** 391 */ 392 393 SSDAsteroid SSDAsteroid::asteroidPool[MAX_ASTEROIDS]; 394 395 #define ASTEROID_MATERIAL "game/SSD/asteroid" 396 397 SSDAsteroid::SSDAsteroid() { 398 } 399 400 SSDAsteroid::~SSDAsteroid() { 401 } 402 403 void SSDAsteroid::WriteToSaveGame( idFile *savefile ) { 404 SSDMover::WriteToSaveGame(savefile); 405 406 savefile->Write(&health, sizeof(health)); 407 } 408 409 void SSDAsteroid::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 410 SSDMover::ReadFromSaveGame(savefile, _game); 411 412 savefile->Read(&health, sizeof(health)); 413 } 414 415 void SSDAsteroid::Init(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) { 416 417 EntityInit(); 418 MoverInit(idVec3(0,0, -_speed), rotate); 419 420 SetGame(_game); 421 422 type = SSD_ENTITY_ASTEROID; 423 424 SetMaterial(ASTEROID_MATERIAL); 425 SetSize(_size); 426 SetRadius(Max(size.x, size.y), 0.3f); 427 SetRotation(game->random.RandomInt(360)); 428 429 430 position = startPosition; 431 432 health = _health; 433 } 434 435 void SSDAsteroid::EntityUpdate() { 436 437 SSDMover::EntityUpdate(); 438 } 439 440 SSDAsteroid* SSDAsteroid::GetNewAsteroid(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) { 441 for(int i = 0; i < MAX_ASTEROIDS; i++) { 442 if(!asteroidPool[i].inUse) { 443 asteroidPool[i].Init(_game, startPosition, _size, _speed, rotate, _health); 444 asteroidPool[i].inUse = true; 445 asteroidPool[i].id = i; 446 447 return &asteroidPool[i]; 448 } 449 } 450 return NULL; 451 } 452 453 SSDAsteroid* SSDAsteroid::GetSpecificAsteroid(int id) { 454 return &asteroidPool[id]; 455 } 456 457 void SSDAsteroid::WriteAsteroids(idFile* savefile) { 458 int count = 0; 459 for(int i = 0; i < MAX_ASTEROIDS; i++) { 460 if(asteroidPool[i].inUse) { 461 count++; 462 } 463 } 464 savefile->Write(&count, sizeof(count)); 465 for(int i = 0; i < MAX_ASTEROIDS; i++) { 466 if(asteroidPool[i].inUse) { 467 savefile->Write(&(asteroidPool[i].id), sizeof(asteroidPool[i].id)); 468 asteroidPool[i].WriteToSaveGame(savefile); 469 } 470 } 471 } 472 473 void SSDAsteroid::ReadAsteroids( idFile* savefile, idGameSSDWindow* _game) { 474 475 int count; 476 savefile->Read(&count, sizeof(count)); 477 for(int i = 0; i < count; i++) { 478 int id; 479 savefile->Read(&id, sizeof(id)); 480 SSDAsteroid* ent = GetSpecificAsteroid(id); 481 ent->ReadFromSaveGame(savefile, _game); 482 } 483 } 484 485 /* 486 ***************************************************************************** 487 * SSDAstronaut 488 **************************************************************************** 489 */ 490 491 SSDAstronaut SSDAstronaut::astronautPool[MAX_ASTRONAUT]; 492 493 #define ASTRONAUT_MATERIAL "game/SSD/astronaut" 494 495 SSDAstronaut::SSDAstronaut() { 496 } 497 498 SSDAstronaut::~SSDAstronaut() { 499 } 500 501 void SSDAstronaut::WriteToSaveGame( idFile *savefile ) { 502 SSDMover::WriteToSaveGame(savefile); 503 504 savefile->Write(&health, sizeof(health)); 505 } 506 507 void SSDAstronaut::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 508 SSDMover::ReadFromSaveGame(savefile, _game); 509 510 savefile->Read(&health, sizeof(health)); 511 } 512 513 void SSDAstronaut::Init(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) { 514 515 EntityInit(); 516 MoverInit(idVec3(0,0, -_speed), rotate); 517 518 SetGame(_game); 519 520 type = SSD_ENTITY_ASTRONAUT; 521 522 SetMaterial(ASTRONAUT_MATERIAL); 523 SetSize(idVec2(256,256)); 524 SetRadius(Max(size.x, size.y), 0.3f); 525 SetRotation(game->random.RandomInt(360)); 526 527 position = startPosition; 528 health = _health; 529 } 530 531 SSDAstronaut* SSDAstronaut::GetNewAstronaut(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) { 532 for(int i = 0; i < MAX_ASTRONAUT; i++) { 533 if(!astronautPool[i].inUse) { 534 astronautPool[i].Init(_game, startPosition, _speed, rotate, _health); 535 astronautPool[i].inUse = true; 536 astronautPool[i].id = i; 537 return &astronautPool[i]; 538 } 539 } 540 return NULL; 541 } 542 543 SSDAstronaut* SSDAstronaut::GetSpecificAstronaut(int id) { 544 return &astronautPool[id]; 545 546 } 547 548 void SSDAstronaut::WriteAstronauts(idFile* savefile) { 549 int count = 0; 550 for(int i = 0; i < MAX_ASTRONAUT; i++) { 551 if(astronautPool[i].inUse) { 552 count++; 553 } 554 } 555 savefile->Write(&count, sizeof(count)); 556 for(int i = 0; i < MAX_ASTRONAUT; i++) { 557 if(astronautPool[i].inUse) { 558 savefile->Write(&(astronautPool[i].id), sizeof(astronautPool[i].id)); 559 astronautPool[i].WriteToSaveGame(savefile); 560 } 561 } 562 } 563 564 void SSDAstronaut::ReadAstronauts(idFile* savefile, idGameSSDWindow* _game) { 565 566 int count; 567 savefile->Read(&count, sizeof(count)); 568 for(int i = 0; i < count; i++) { 569 int id; 570 savefile->Read(&id, sizeof(id)); 571 SSDAstronaut* ent = GetSpecificAstronaut(id); 572 ent->ReadFromSaveGame(savefile, _game); 573 } 574 } 575 576 /* 577 ***************************************************************************** 578 * SSDExplosion 579 **************************************************************************** 580 */ 581 582 SSDExplosion SSDExplosion::explosionPool[MAX_EXPLOSIONS]; 583 584 585 //#define EXPLOSION_MATERIAL "game/SSD/fball" 586 //#define EXPLOSION_TELEPORT "game/SSD/teleport" 587 588 const char* explosionMaterials[] = { 589 "game/SSD/fball", 590 "game/SSD/teleport" 591 }; 592 593 #define EXPLOSION_MATERIAL_COUNT 2 594 595 SSDExplosion::SSDExplosion() { 596 type = SSD_ENTITY_EXPLOSION; 597 } 598 599 SSDExplosion::~SSDExplosion() { 600 } 601 602 void SSDExplosion::WriteToSaveGame( idFile *savefile ) { 603 SSDEntity::WriteToSaveGame(savefile); 604 605 savefile->Write(&finalSize, sizeof(finalSize)); 606 savefile->Write(&length, sizeof(length)); 607 savefile->Write(&beginTime, sizeof(beginTime)); 608 savefile->Write(&endTime, sizeof(endTime)); 609 savefile->Write(&explosionType, sizeof(explosionType)); 610 611 612 savefile->Write(&(buddy->type), sizeof(buddy->type)); 613 savefile->Write(&(buddy->id), sizeof(buddy->id)); 614 615 savefile->Write(&killBuddy, sizeof(killBuddy)); 616 savefile->Write(&followBuddy, sizeof(followBuddy)); 617 } 618 619 void SSDExplosion::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 620 SSDEntity::ReadFromSaveGame(savefile, _game); 621 622 savefile->Read(&finalSize, sizeof(finalSize)); 623 savefile->Read(&length, sizeof(length)); 624 savefile->Read(&beginTime, sizeof(beginTime)); 625 savefile->Read(&endTime, sizeof(endTime)); 626 savefile->Read(&explosionType, sizeof(explosionType)); 627 628 int type, id; 629 savefile->Read(&type, sizeof(type)); 630 savefile->Read(&id, sizeof(id)); 631 632 //Get a pointer to my buddy 633 buddy = _game->GetSpecificEntity(type, id); 634 635 savefile->Read(&killBuddy, sizeof(killBuddy)); 636 savefile->Read(&followBuddy, sizeof(followBuddy)); 637 } 638 639 void SSDExplosion::Init(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) { 640 641 EntityInit(); 642 643 SetGame(_game); 644 645 type = SSD_ENTITY_EXPLOSION; 646 explosionType = _type; 647 648 SetMaterial(explosionMaterials[explosionType]); 649 SetPosition(_position); 650 position.z -= 50; 651 652 finalSize = _size; 653 length = _length; 654 beginTime = game->ssdTime; 655 endTime = beginTime + length; 656 657 buddy = _buddy; 658 killBuddy = _killBuddy; 659 followBuddy = _followBuddy; 660 661 //Explosion Starts from nothing and will increase in size until it gets to final size 662 size.Zero(); 663 664 noPlayerDamage = true; 665 noHit = true; 666 } 667 668 void SSDExplosion::EntityUpdate() { 669 670 SSDEntity::EntityUpdate(); 671 672 //Always set my position to my buddies position except change z to be on top 673 if(followBuddy) { 674 position = buddy->position; 675 position.z -= 50; 676 } else { 677 //Only mess with the z if we are not following 678 position.z = buddy->position.z - 50; 679 } 680 681 //Scale the image based on the time 682 size = finalSize*((float)(currentTime-beginTime)/(float)length); 683 684 //Destroy myself after the explosion is done 685 if(currentTime > endTime) { 686 destroyed = true; 687 688 if(killBuddy) { 689 //Destroy the exploding object 690 buddy->destroyed = true; 691 } 692 } 693 } 694 695 SSDExplosion* SSDExplosion::GetNewExplosion(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) { 696 for(int i = 0; i < MAX_EXPLOSIONS; i++) { 697 if(!explosionPool[i].inUse) { 698 explosionPool[i].Init(_game, _position, _size, _length, _type, _buddy, _killBuddy, _followBuddy); 699 explosionPool[i].inUse = true; 700 return &explosionPool[i]; 701 } 702 } 703 return NULL; 704 } 705 706 SSDExplosion* SSDExplosion::GetSpecificExplosion(int id) { 707 return &explosionPool[id]; 708 } 709 710 void SSDExplosion::WriteExplosions(idFile* savefile) { 711 int count = 0; 712 for(int i = 0; i < MAX_EXPLOSIONS; i++) { 713 if(explosionPool[i].inUse) { 714 count++; 715 } 716 } 717 savefile->Write(&count, sizeof(count)); 718 for(int i = 0; i < MAX_EXPLOSIONS; i++) { 719 if(explosionPool[i].inUse) { 720 savefile->Write(&(explosionPool[i].id), sizeof(explosionPool[i].id)); 721 explosionPool[i].WriteToSaveGame(savefile); 722 } 723 } 724 } 725 726 void SSDExplosion::ReadExplosions(idFile* savefile, idGameSSDWindow* _game) { 727 728 int count; 729 savefile->Read(&count, sizeof(count)); 730 for(int i = 0; i < count; i++) { 731 int id; 732 savefile->Read(&id, sizeof(id)); 733 SSDExplosion* ent = GetSpecificExplosion(id); 734 ent->ReadFromSaveGame(savefile, _game); 735 } 736 } 737 738 /* 739 ***************************************************************************** 740 * SSDPoints 741 **************************************************************************** 742 */ 743 744 SSDPoints SSDPoints::pointsPool[MAX_POINTS]; 745 746 SSDPoints::SSDPoints() { 747 type = SSD_ENTITY_POINTS; 748 } 749 750 SSDPoints::~SSDPoints() { 751 } 752 753 void SSDPoints::WriteToSaveGame( idFile *savefile ) { 754 SSDEntity::WriteToSaveGame(savefile); 755 756 savefile->Write(&length, sizeof(length)); 757 savefile->Write(&distance, sizeof(distance)); 758 savefile->Write(&beginTime, sizeof(beginTime)); 759 savefile->Write(&endTime, sizeof(endTime)); 760 761 savefile->Write(&beginPosition, sizeof(beginPosition)); 762 savefile->Write(&endPosition, sizeof(endPosition)); 763 764 savefile->Write(&beginColor, sizeof(beginColor)); 765 savefile->Write(&endColor, sizeof(endColor)); 766 767 } 768 769 void SSDPoints::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 770 SSDEntity::ReadFromSaveGame(savefile, _game); 771 772 savefile->Read(&length, sizeof(length)); 773 savefile->Read(&distance, sizeof(distance)); 774 savefile->Read(&beginTime, sizeof(beginTime)); 775 savefile->Read(&endTime, sizeof(endTime)); 776 777 savefile->Read(&beginPosition, sizeof(beginPosition)); 778 savefile->Read(&endPosition, sizeof(endPosition)); 779 780 savefile->Read(&beginColor, sizeof(beginColor)); 781 savefile->Read(&endColor, sizeof(endColor)); 782 } 783 784 void SSDPoints::Init(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) { 785 786 EntityInit(); 787 788 SetGame(_game); 789 790 length = _length; 791 distance = _distance; 792 beginTime = game->ssdTime; 793 endTime = beginTime + length; 794 795 textScale = 0.4f; 796 text = va("%d", _points); 797 798 float width = 0; 799 for(int i = 0; i < text.Length(); i++) { 800 width += dc->CharWidth(text[i], textScale); 801 } 802 803 size.Set(0,0); 804 805 //Set the start position at the top of the passed in entity 806 position = WorldToScreen(_ent->position); 807 position = ScreenToWorld(position); 808 809 position.z = 0; 810 position.x -= (width/2.0f); 811 812 beginPosition = position; 813 814 endPosition = beginPosition; 815 endPosition.y += _distance; 816 817 //beginColor.Set(0,1,0,1); 818 endColor.Set(1,1,1,0); 819 820 beginColor = color; 821 beginColor.w = 1; 822 823 noPlayerDamage = true; 824 noHit = true; 825 } 826 827 void SSDPoints::EntityUpdate() { 828 829 float t = (float)(currentTime - beginTime)/(float)length; 830 831 //Move up from the start position 832 position.Lerp(beginPosition, endPosition, t); 833 834 //Interpolate the color 835 foreColor.Lerp(beginColor, endColor, t); 836 837 if(currentTime > endTime) { 838 destroyed = true; 839 } 840 } 841 842 SSDPoints* SSDPoints::GetNewPoints(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) { 843 for(int i = 0; i < MAX_POINTS; i++) { 844 if(!pointsPool[i].inUse) { 845 pointsPool[i].Init(_game, _ent, _points, _length, _distance, color); 846 pointsPool[i].inUse = true; 847 return &pointsPool[i]; 848 } 849 } 850 return NULL; 851 } 852 853 SSDPoints* SSDPoints::GetSpecificPoints(int id) { 854 return &pointsPool[id]; 855 } 856 857 void SSDPoints::WritePoints(idFile* savefile) { 858 int count = 0; 859 for(int i = 0; i < MAX_POINTS; i++) { 860 if(pointsPool[i].inUse) { 861 count++; 862 } 863 } 864 savefile->Write(&count, sizeof(count)); 865 for(int i = 0; i < MAX_POINTS; i++) { 866 if(pointsPool[i].inUse) { 867 savefile->Write(&(pointsPool[i].id), sizeof(pointsPool[i].id)); 868 pointsPool[i].WriteToSaveGame(savefile); 869 } 870 } 871 } 872 873 void SSDPoints::ReadPoints(idFile* savefile, idGameSSDWindow* _game) { 874 875 int count; 876 savefile->Read(&count, sizeof(count)); 877 for(int i = 0; i < count; i++) { 878 int id; 879 savefile->Read(&id, sizeof(id)); 880 SSDPoints* ent = GetSpecificPoints(id); 881 ent->ReadFromSaveGame(savefile, _game); 882 } 883 } 884 885 /* 886 ***************************************************************************** 887 * SSDProjectile 888 **************************************************************************** 889 */ 890 891 SSDProjectile SSDProjectile::projectilePool[MAX_PROJECTILES]; 892 893 #define PROJECTILE_MATERIAL "game/SSD/fball" 894 895 SSDProjectile::SSDProjectile() { 896 type = SSD_ENTITY_PROJECTILE; 897 } 898 899 SSDProjectile::~SSDProjectile() { 900 } 901 902 void SSDProjectile::WriteToSaveGame( idFile *savefile ) { 903 SSDEntity::WriteToSaveGame(savefile); 904 905 savefile->Write(&dir, sizeof(dir)); 906 savefile->Write(&speed, sizeof(speed)); 907 savefile->Write(&beginTime, sizeof(beginTime)); 908 savefile->Write(&endTime, sizeof(endTime)); 909 910 savefile->Write(&endPosition, sizeof(endPosition)); 911 } 912 913 void SSDProjectile::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 914 SSDEntity::ReadFromSaveGame(savefile, _game); 915 916 savefile->Read(&dir, sizeof(dir)); 917 savefile->Read(&speed, sizeof(speed)); 918 savefile->Read(&beginTime, sizeof(beginTime)); 919 savefile->Read(&endTime, sizeof(endTime)); 920 921 savefile->Read(&endPosition, sizeof(endPosition)); 922 } 923 924 void SSDProjectile::Init(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) { 925 926 EntityInit(); 927 928 SetGame(_game); 929 930 SetMaterial(PROJECTILE_MATERIAL); 931 size.Set(_size,_size); 932 933 position = _beginPosition; 934 endPosition = _endPosition; 935 936 dir = _endPosition - position; 937 dir.Normalize(); 938 939 //speed.Zero(); 940 speed.x = speed.y = speed.z = _speed; 941 942 noHit = true; 943 } 944 945 void SSDProjectile::EntityUpdate() { 946 947 SSDEntity::EntityUpdate(); 948 949 //Move forward based on speed (units per second) 950 idVec3 moved = dir*((float)elapsed/1000.0f)*speed.z; 951 position += moved; 952 953 if(position.z > endPosition.z) { 954 //We have reached our position 955 destroyed = true; 956 } 957 } 958 959 SSDProjectile* SSDProjectile::GetNewProjectile(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) { 960 for(int i = 0; i < MAX_PROJECTILES; i++) { 961 if(!projectilePool[i].inUse) { 962 projectilePool[i].Init(_game, _beginPosition, _endPosition, _speed, _size); 963 projectilePool[i].inUse = true; 964 return &projectilePool[i]; 965 } 966 } 967 return NULL; 968 } 969 970 SSDProjectile* SSDProjectile::GetSpecificProjectile(int id) { 971 return &projectilePool[id]; 972 } 973 974 void SSDProjectile::WriteProjectiles(idFile* savefile) { 975 int count = 0; 976 for(int i = 0; i < MAX_PROJECTILES; i++) { 977 if(projectilePool[i].inUse) { 978 count++; 979 } 980 } 981 savefile->Write(&count, sizeof(count)); 982 for(int i = 0; i < MAX_PROJECTILES; i++) { 983 if(projectilePool[i].inUse) { 984 savefile->Write(&(projectilePool[i].id), sizeof(projectilePool[i].id)); 985 projectilePool[i].WriteToSaveGame(savefile); 986 } 987 } 988 } 989 990 void SSDProjectile::ReadProjectiles(idFile* savefile, idGameSSDWindow* _game) { 991 992 int count; 993 savefile->Read(&count, sizeof(count)); 994 for(int i = 0; i < count; i++) { 995 int id; 996 savefile->Read(&id, sizeof(id)); 997 SSDProjectile* ent = GetSpecificProjectile(id); 998 ent->ReadFromSaveGame(savefile, _game); 999 } 1000 } 1001 1002 /* 1003 ***************************************************************************** 1004 * SSDPowerup 1005 **************************************************************************** 1006 */ 1007 1008 const char* powerupMaterials[][2] = { 1009 "game/SSD/powerupHealthClosed", "game/SSD/powerupHealthOpen", 1010 "game/SSD/powerupSuperBlasterClosed", "game/SSD/powerupSuperBlasterOpen", 1011 "game/SSD/powerupNukeClosed", "game/SSD/powerupNukeOpen", 1012 "game/SSD/powerupRescueClosed", "game/SSD/powerupRescueOpen", 1013 "game/SSD/powerupBonusPointsClosed", "game/SSD/powerupBonusPointsOpen", 1014 "game/SSD/powerupDamageClosed", "game/SSD/powerupDamageOpen", 1015 }; 1016 1017 #define POWERUP_MATERIAL_COUNT 6 1018 1019 SSDPowerup SSDPowerup::powerupPool[MAX_POWERUPS]; 1020 1021 SSDPowerup::SSDPowerup() { 1022 1023 } 1024 1025 SSDPowerup::~SSDPowerup() { 1026 } 1027 1028 void SSDPowerup::WriteToSaveGame( idFile *savefile ) { 1029 SSDMover::WriteToSaveGame(savefile); 1030 1031 savefile->Write(&powerupState, sizeof(powerupState)); 1032 savefile->Write(&powerupType, sizeof(powerupType)); 1033 } 1034 1035 void SSDPowerup::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) { 1036 SSDMover::ReadFromSaveGame(savefile, _game); 1037 1038 savefile->Read(&powerupState, sizeof(powerupState)); 1039 savefile->Read(&powerupType, sizeof(powerupType)); 1040 } 1041 1042 void SSDPowerup::OnHit(int key) { 1043 1044 if(powerupState == POWERUP_STATE_CLOSED) { 1045 1046 //Small explosion to indicate it is opened 1047 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2.0f, 300, SSDExplosion::EXPLOSION_NORMAL, this, false, true); 1048 game->entities.Append(explosion); 1049 1050 1051 powerupState = POWERUP_STATE_OPEN; 1052 SetMaterial(powerupMaterials[powerupType][powerupState]); 1053 } else { 1054 //Destory the powerup with a big explosion 1055 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2, 300, SSDExplosion::EXPLOSION_NORMAL, this); 1056 game->entities.Append(explosion); 1057 game->PlaySound("arcade_explode"); 1058 1059 noHit = true; 1060 noPlayerDamage = true; 1061 } 1062 } 1063 1064 void SSDPowerup::OnStrikePlayer() { 1065 1066 if(powerupState == POWERUP_STATE_OPEN) { 1067 //The powerup was open so activate it 1068 OnActivatePowerup(); 1069 } 1070 1071 //Just destroy the powerup 1072 destroyed = true; 1073 } 1074 1075 void SSDPowerup::OnOpenPowerup() { 1076 } 1077 1078 void SSDPowerup::OnActivatePowerup() { 1079 switch(powerupType) { 1080 case POWERUP_TYPE_HEALTH: 1081 { 1082 game->AddHealth(10); 1083 break; 1084 } 1085 case POWERUP_TYPE_SUPER_BLASTER: 1086 { 1087 game->OnSuperBlaster(); 1088 break; 1089 } 1090 case POWERUP_TYPE_ASTEROID_NUKE: 1091 { 1092 game->OnNuke(); 1093 break; 1094 } 1095 case POWERUP_TYPE_RESCUE_ALL: 1096 { 1097 game->OnRescueAll(); 1098 break; 1099 } 1100 case POWERUP_TYPE_BONUS_POINTS: 1101 { 1102 int points = (game->random.RandomInt(5)+1) * 100; 1103 game->AddScore(this, points); 1104 break; 1105 } 1106 case POWERUP_TYPE_DAMAGE: 1107 { 1108 game->AddDamage(10); 1109 game->PlaySound("arcade_explode"); 1110 break; 1111 } 1112 1113 } 1114 } 1115 1116 1117 void SSDPowerup::Init(idGameSSDWindow* _game, float _speed, float _rotation) { 1118 1119 EntityInit(); 1120 MoverInit(idVec3(0,0, -_speed), _rotation); 1121 1122 SetGame(_game); 1123 SetSize(idVec2(200,200)); 1124 SetRadius(Max(size.x, size.y), 0.3f); 1125 1126 type = SSD_ENTITY_POWERUP; 1127 1128 idVec3 startPosition; 1129 startPosition.x = game->random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f); 1130 startPosition.y = game->random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f); 1131 startPosition.z = ENTITY_START_DIST; 1132 1133 position = startPosition; 1134 //SetPosition(startPosition); 1135 1136 powerupState = POWERUP_STATE_CLOSED; 1137 powerupType = game->random.RandomInt(POWERUP_TYPE_MAX+1); 1138 if(powerupType >= POWERUP_TYPE_MAX) { 1139 powerupType = 0; 1140 } 1141 1142 /*OutputDebugString(va("Powerup: %d\n", powerupType)); 1143 if(powerupType == 0) { 1144 int x = 0; 1145 }*/ 1146 1147 SetMaterial(powerupMaterials[powerupType][powerupState]); 1148 } 1149 1150 SSDPowerup* SSDPowerup::GetNewPowerup(idGameSSDWindow* _game, float _speed, float _rotation) { 1151 1152 for(int i = 0; i < MAX_POWERUPS; i++) { 1153 if(!powerupPool[i].inUse) { 1154 powerupPool[i].Init(_game, _speed, _rotation); 1155 powerupPool[i].inUse = true; 1156 return &powerupPool[i]; 1157 } 1158 } 1159 return NULL; 1160 } 1161 1162 SSDPowerup* SSDPowerup::GetSpecificPowerup(int id) { 1163 return &powerupPool[id]; 1164 } 1165 1166 void SSDPowerup::WritePowerups(idFile* savefile) { 1167 int count = 0; 1168 for(int i = 0; i < MAX_POWERUPS; i++) { 1169 if(powerupPool[i].inUse) { 1170 count++; 1171 } 1172 } 1173 savefile->Write(&count, sizeof(count)); 1174 for(int i = 0; i < MAX_POWERUPS; i++) { 1175 if(powerupPool[i].inUse) { 1176 savefile->Write(&(powerupPool[i].id), sizeof(powerupPool[i].id)); 1177 powerupPool[i].WriteToSaveGame(savefile); 1178 } 1179 } 1180 } 1181 1182 void SSDPowerup::ReadPowerups(idFile* savefile, idGameSSDWindow* _game) { 1183 1184 int count; 1185 savefile->Read(&count, sizeof(count)); 1186 for(int i = 0; i < count; i++) { 1187 int id; 1188 savefile->Read(&id, sizeof(id)); 1189 SSDPowerup* ent = GetSpecificPowerup(id); 1190 ent->ReadFromSaveGame(savefile, _game); 1191 } 1192 } 1193 1194 /* 1195 ***************************************************************************** 1196 * idGameSSDWindow 1197 **************************************************************************** 1198 */ 1199 1200 idRandom idGameSSDWindow::random; 1201 1202 idGameSSDWindow::idGameSSDWindow(idUserInterfaceLocal *g) : idWindow(g) { 1203 gui = g; 1204 CommonInit(); 1205 } 1206 1207 idGameSSDWindow::~idGameSSDWindow() { 1208 ResetGameStats(); 1209 } 1210 1211 void idGameSSDWindow::WriteToSaveGame( idFile *savefile ) { 1212 idWindow::WriteToSaveGame(savefile); 1213 1214 savefile->Write(&ssdTime, sizeof(ssdTime)); 1215 1216 beginLevel.WriteToSaveGame(savefile); 1217 resetGame.WriteToSaveGame(savefile); 1218 continueGame.WriteToSaveGame(savefile); 1219 refreshGuiData.WriteToSaveGame(savefile); 1220 1221 crosshair.WriteToSaveGame(savefile); 1222 savefile->Write(&screenBounds, sizeof(screenBounds)); 1223 1224 savefile->Write(&levelCount, sizeof(levelCount)); 1225 for(int i = 0; i < levelCount; i++) { 1226 savefile->Write(&(levelData[i]), sizeof(SSDLevelData_t)); 1227 savefile->Write(&(asteroidData[i]), sizeof(SSDAsteroidData_t)); 1228 savefile->Write(&(astronautData[i]), sizeof(SSDAstronautData_t)); 1229 savefile->Write(&(powerupData[i]), sizeof(SSDPowerupData_t)); 1230 } 1231 1232 savefile->Write(&weaponCount, sizeof(weaponCount)); 1233 for(int i = 0; i < weaponCount; i++) { 1234 savefile->Write(&(weaponData[i]), sizeof(SSDWeaponData_t)); 1235 } 1236 1237 savefile->Write(&superBlasterTimeout, sizeof(superBlasterTimeout)); 1238 savefile->Write(&gameStats, sizeof(SSDGameStats_t)); 1239 1240 //Write All Static Entities 1241 SSDAsteroid::WriteAsteroids(savefile); 1242 SSDAstronaut::WriteAstronauts(savefile); 1243 SSDExplosion::WriteExplosions(savefile); 1244 SSDPoints::WritePoints(savefile); 1245 SSDProjectile::WriteProjectiles(savefile); 1246 SSDPowerup::WritePowerups(savefile); 1247 1248 int entCount = entities.Num(); 1249 savefile->Write(&entCount, sizeof(entCount)); 1250 for(int i = 0; i < entCount; i++) { 1251 savefile->Write(&(entities[i]->type), sizeof(entities[i]->type)); 1252 savefile->Write(&(entities[i]->id), sizeof(entities[i]->id)); 1253 } 1254 } 1255 1256 void idGameSSDWindow::ReadFromSaveGame( idFile *savefile ) { 1257 idWindow::ReadFromSaveGame(savefile); 1258 1259 1260 savefile->Read(&ssdTime, sizeof(ssdTime)); 1261 1262 beginLevel.ReadFromSaveGame(savefile); 1263 resetGame.ReadFromSaveGame(savefile); 1264 continueGame.ReadFromSaveGame(savefile); 1265 refreshGuiData.ReadFromSaveGame(savefile); 1266 1267 crosshair.ReadFromSaveGame(savefile); 1268 savefile->Read(&screenBounds, sizeof(screenBounds)); 1269 1270 savefile->Read(&levelCount, sizeof(levelCount)); 1271 for(int i = 0; i < levelCount; i++) { 1272 SSDLevelData_t newLevel; 1273 savefile->Read(&newLevel, sizeof(SSDLevelData_t)); 1274 levelData.Append(newLevel); 1275 1276 SSDAsteroidData_t newAsteroid; 1277 savefile->Read(&newAsteroid, sizeof(SSDAsteroidData_t)); 1278 asteroidData.Append(newAsteroid); 1279 1280 SSDAstronautData_t newAstronaut; 1281 savefile->Read(&newAstronaut, sizeof(SSDAstronautData_t)); 1282 astronautData.Append(newAstronaut); 1283 1284 SSDPowerupData_t newPowerup; 1285 savefile->Read(&newPowerup, sizeof(SSDPowerupData_t)); 1286 powerupData.Append(newPowerup); 1287 } 1288 1289 savefile->Read(&weaponCount, sizeof(weaponCount)); 1290 for(int i = 0; i < weaponCount; i++) { 1291 SSDWeaponData_t newWeapon; 1292 savefile->Read(&newWeapon, sizeof(SSDWeaponData_t)); 1293 weaponData.Append(newWeapon); 1294 } 1295 1296 savefile->Read(&superBlasterTimeout, sizeof(superBlasterTimeout)); 1297 1298 savefile->Read(&gameStats, sizeof(SSDGameStats_t)); 1299 //Reset this because it is no longer valid 1300 gameStats.levelStats.targetEnt = NULL; 1301 1302 SSDAsteroid::ReadAsteroids(savefile, this); 1303 SSDAstronaut::ReadAstronauts(savefile, this); 1304 SSDExplosion::ReadExplosions(savefile, this); 1305 SSDPoints::ReadPoints(savefile, this); 1306 SSDProjectile::ReadProjectiles(savefile, this); 1307 SSDPowerup::ReadPowerups(savefile, this); 1308 1309 int entCount; 1310 savefile->Read(&entCount, sizeof(entCount)); 1311 1312 for(int i = 0; i < entCount; i++) { 1313 int type, id; 1314 savefile->Read(&type, sizeof(type)); 1315 savefile->Read(&id, sizeof(id)); 1316 1317 SSDEntity* ent = GetSpecificEntity(type, id); 1318 if(ent) { 1319 entities.Append(ent); 1320 } 1321 } 1322 } 1323 1324 const char *idGameSSDWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) { 1325 1326 // need to call this to allow proper focus and capturing on embedded children 1327 const char *ret = idWindow::HandleEvent(event, updateVisuals); 1328 1329 if(!gameStats.gameRunning) { 1330 return ret; 1331 } 1332 1333 int key = event->evValue; 1334 1335 if ( event->evType == SE_KEY ) { 1336 1337 if ( !event->evValue2 ) { 1338 return ret; 1339 } 1340 1341 if ( key == K_MOUSE1 || key == K_MOUSE2) { 1342 FireWeapon(key); 1343 } else { 1344 return ret; 1345 } 1346 } 1347 return ret; 1348 } 1349 1350 idWinVar *idGameSSDWindow::GetWinVarByName (const char *_name, bool winLookup, drawWin_t** owner) { 1351 1352 idWinVar *retVar = NULL; 1353 1354 if (idStr::Icmp(_name, "beginLevel") == 0) { 1355 retVar = &beginLevel; 1356 } 1357 1358 if (idStr::Icmp(_name, "resetGame") == 0) { 1359 retVar = &resetGame; 1360 } 1361 1362 if (idStr::Icmp(_name, "continueGame") == 0) { 1363 retVar = &continueGame; 1364 } 1365 if (idStr::Icmp(_name, "refreshGuiData") == 0) { 1366 retVar = &refreshGuiData; 1367 } 1368 1369 1370 if(retVar) { 1371 return retVar; 1372 } 1373 1374 return idWindow::GetWinVarByName(_name, winLookup, owner); 1375 } 1376 1377 1378 void idGameSSDWindow::Draw(int time, float x, float y) { 1379 1380 //Update the game every frame before drawing 1381 UpdateGame(); 1382 1383 RefreshGuiData(); 1384 1385 if(gameStats.gameRunning) { 1386 1387 ZOrderEntities(); 1388 1389 //Draw from back to front 1390 for(int i = entities.Num()-1; i >= 0; i--) { 1391 entities[i]->Draw(); 1392 } 1393 1394 //The last thing to draw is the crosshair 1395 idVec2 cursor; 1396 //GetCursor(cursor); 1397 cursor.x = gui->CursorX(); 1398 cursor.y = gui->CursorY(); 1399 1400 crosshair.Draw(cursor); 1401 } 1402 } 1403 1404 1405 bool idGameSSDWindow::ParseInternalVar(const char *_name, idTokenParser *src) { 1406 1407 if (idStr::Icmp(_name, "beginLevel") == 0) { 1408 beginLevel = src->ParseBool(); 1409 return true; 1410 } 1411 if (idStr::Icmp(_name, "resetGame") == 0) { 1412 resetGame = src->ParseBool(); 1413 return true; 1414 } 1415 if (idStr::Icmp(_name, "continueGame") == 0) { 1416 continueGame = src->ParseBool(); 1417 return true; 1418 } 1419 if (idStr::Icmp(_name, "refreshGuiData") == 0) { 1420 refreshGuiData = src->ParseBool(); 1421 return true; 1422 } 1423 1424 if(idStr::Icmp(_name, "levelcount") == 0) { 1425 levelCount = src->ParseInt(); 1426 for(int i = 0; i < levelCount; i++) { 1427 SSDLevelData_t newLevel; 1428 memset(&newLevel, 0, sizeof(SSDLevelData_t)); 1429 levelData.Append(newLevel); 1430 1431 SSDAsteroidData_t newAsteroid; 1432 memset(&newAsteroid, 0, sizeof(SSDAsteroidData_t)); 1433 asteroidData.Append(newAsteroid); 1434 1435 SSDAstronautData_t newAstronaut; 1436 memset(&newAstronaut, 0, sizeof(SSDAstronautData_t)); 1437 astronautData.Append(newAstronaut); 1438 1439 SSDPowerupData_t newPowerup; 1440 memset(&newPowerup, 0, sizeof(SSDPowerupData_t)); 1441 powerupData.Append(newPowerup); 1442 1443 1444 } 1445 return true; 1446 } 1447 if(idStr::Icmp(_name, "weaponCount") == 0) { 1448 weaponCount = src->ParseInt(); 1449 for(int i = 0; i < weaponCount; i++) { 1450 SSDWeaponData_t newWeapon; 1451 memset(&newWeapon, 0, sizeof(SSDWeaponData_t)); 1452 weaponData.Append(newWeapon); 1453 } 1454 return true; 1455 } 1456 1457 if(idStr::FindText(_name, "leveldata", false) >= 0) { 1458 idStr tempName = _name; 1459 int level = atoi(tempName.Right(2))-1; 1460 1461 idStr levelData; 1462 ParseString(src, levelData); 1463 ParseLevelData(level, levelData); 1464 return true; 1465 } 1466 1467 if(idStr::FindText(_name, "asteroiddata", false) >= 0) { 1468 idStr tempName = _name; 1469 int level = atoi(tempName.Right(2))-1; 1470 1471 idStr asteroidData; 1472 ParseString(src, asteroidData); 1473 ParseAsteroidData(level, asteroidData); 1474 return true; 1475 } 1476 1477 if(idStr::FindText(_name, "weapondata", false) >= 0) { 1478 idStr tempName = _name; 1479 int weapon = atoi(tempName.Right(2))-1; 1480 1481 idStr weaponData; 1482 ParseString(src, weaponData); 1483 ParseWeaponData(weapon, weaponData); 1484 return true; 1485 } 1486 1487 if(idStr::FindText(_name, "astronautdata", false) >= 0) { 1488 idStr tempName = _name; 1489 int level = atoi(tempName.Right(2))-1; 1490 1491 idStr astronautData; 1492 ParseString(src, astronautData); 1493 ParseAstronautData(level, astronautData); 1494 return true; 1495 } 1496 1497 if(idStr::FindText(_name, "powerupdata", false) >= 0) { 1498 idStr tempName = _name; 1499 int level = atoi(tempName.Right(2))-1; 1500 1501 idStr powerupData; 1502 ParseString(src, powerupData); 1503 ParsePowerupData(level, powerupData); 1504 return true; 1505 } 1506 1507 return idWindow::ParseInternalVar(_name, src); 1508 } 1509 1510 void idGameSSDWindow::ParseLevelData(int level, const idStr& levelDataString) { 1511 1512 idParser parser; 1513 idToken token; 1514 parser.LoadMemory(levelDataString.c_str(), levelDataString.Length(), "LevelData"); 1515 1516 levelData[level].spawnBuffer = parser.ParseFloat(); 1517 levelData[level].needToWin = parser.ParseInt(); //Required Destroyed 1518 1519 } 1520 1521 void idGameSSDWindow::ParseAsteroidData(int level, const idStr& asteroidDataString) { 1522 1523 idParser parser; 1524 idToken token; 1525 parser.LoadMemory(asteroidDataString.c_str(), asteroidDataString.Length(), "AsteroidData"); 1526 1527 asteroidData[level].speedMin = parser.ParseFloat(); //Speed Min 1528 asteroidData[level].speedMax = parser.ParseFloat(); //Speed Max 1529 1530 asteroidData[level].sizeMin = parser.ParseFloat(); //Size Min 1531 asteroidData[level].sizeMax = parser.ParseFloat(); //Size Max 1532 1533 asteroidData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second) 1534 asteroidData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second) 1535 1536 asteroidData[level].spawnMin = parser.ParseInt(); //Spawn Min 1537 asteroidData[level].spawnMax = parser.ParseInt(); //Spawn Max 1538 1539 asteroidData[level].asteroidHealth = parser.ParseInt(); //Health of the asteroid 1540 asteroidData[level].asteroidDamage = parser.ParseInt(); //Asteroid Damage 1541 asteroidData[level].asteroidPoints = parser.ParseInt(); //Points awarded for destruction 1542 } 1543 1544 void idGameSSDWindow::ParsePowerupData(int level, const idStr& powerupDataString) { 1545 1546 idParser parser; 1547 idToken token; 1548 parser.LoadMemory(powerupDataString.c_str(), powerupDataString.Length(), "PowerupData"); 1549 1550 powerupData[level].speedMin = parser.ParseFloat(); //Speed Min 1551 powerupData[level].speedMax = parser.ParseFloat(); //Speed Max 1552 1553 powerupData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second) 1554 powerupData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second) 1555 1556 powerupData[level].spawnMin = parser.ParseInt(); //Spawn Min 1557 powerupData[level].spawnMax = parser.ParseInt(); //Spawn Max 1558 1559 } 1560 1561 void idGameSSDWindow::ParseWeaponData(int weapon, const idStr& weaponDataString) { 1562 1563 idParser parser; 1564 idToken token; 1565 parser.LoadMemory(weaponDataString.c_str(), weaponDataString.Length(), "WeaponData"); 1566 1567 weaponData[weapon].speed = parser.ParseFloat(); 1568 weaponData[weapon].damage = parser.ParseFloat(); 1569 weaponData[weapon].size = parser.ParseFloat(); 1570 } 1571 1572 void idGameSSDWindow::ParseAstronautData(int level, const idStr& astronautDataString) { 1573 1574 idParser parser; 1575 idToken token; 1576 parser.LoadMemory(astronautDataString.c_str(), astronautDataString.Length(), "AstronautData"); 1577 1578 astronautData[level].speedMin = parser.ParseFloat(); //Speed Min 1579 astronautData[level].speedMax = parser.ParseFloat(); //Speed Max 1580 1581 astronautData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second) 1582 astronautData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second) 1583 1584 astronautData[level].spawnMin = parser.ParseInt(); //Spawn Min 1585 astronautData[level].spawnMax = parser.ParseInt(); //Spawn Max 1586 1587 astronautData[level].health = parser.ParseInt(); //Health of the asteroid 1588 astronautData[level].points = parser.ParseInt(); //Asteroid Damage 1589 astronautData[level].penalty = parser.ParseInt(); //Points awarded for destruction 1590 } 1591 1592 void idGameSSDWindow::CommonInit() { 1593 crosshair.InitCrosshairs(); 1594 1595 1596 beginLevel = false; 1597 resetGame = false; 1598 continueGame = false; 1599 refreshGuiData = false; 1600 1601 ssdTime = 0; 1602 levelCount = 0; 1603 weaponCount = 0; 1604 screenBounds = idBounds(idVec3(-320,-240,0), idVec3(320,240,0)); 1605 1606 superBlasterTimeout = 0; 1607 1608 currentSound = 0; 1609 1610 //Precahce all assets that are loaded dynamically 1611 declManager->FindMaterial(ASTEROID_MATERIAL); 1612 declManager->FindMaterial(ASTRONAUT_MATERIAL); 1613 1614 for(int i = 0; i < EXPLOSION_MATERIAL_COUNT; i++) { 1615 declManager->FindMaterial(explosionMaterials[i]); 1616 } 1617 declManager->FindMaterial(PROJECTILE_MATERIAL); 1618 for(int i = 0; i < POWERUP_MATERIAL_COUNT; i++) { 1619 declManager->FindMaterial(powerupMaterials[i][0]); 1620 declManager->FindMaterial(powerupMaterials[i][1]); 1621 } 1622 1623 // Precache sounds 1624 declManager->FindSound( "arcade_blaster" ); 1625 declManager->FindSound( "arcade_capture" ); 1626 declManager->FindSound( "arcade_explode" ); 1627 1628 ResetGameStats(); 1629 } 1630 1631 void idGameSSDWindow::ResetGameStats() { 1632 1633 ResetEntities(); 1634 1635 //Reset the gamestats structure 1636 memset(&gameStats, 0, sizeof(gameStats)); 1637 1638 gameStats.health = 100; 1639 1640 } 1641 1642 void idGameSSDWindow::ResetLevelStats() { 1643 1644 ResetEntities(); 1645 1646 //Reset the level statistics structure 1647 memset(&gameStats.levelStats, 0, sizeof(gameStats.levelStats)); 1648 1649 1650 } 1651 1652 void idGameSSDWindow::ResetEntities() { 1653 //Destroy all of the entities 1654 for(int i = 0; i < entities.Num(); i++) { 1655 entities[i]->DestroyEntity(); 1656 } 1657 entities.Clear(); 1658 } 1659 1660 void idGameSSDWindow::StartGame() { 1661 1662 gameStats.gameRunning = true; 1663 } 1664 1665 void idGameSSDWindow::StopGame() { 1666 1667 gameStats.gameRunning = false; 1668 } 1669 1670 void idGameSSDWindow::GameOver() { 1671 1672 1673 StopGame(); 1674 1675 gui->HandleNamedEvent("gameOver"); 1676 } 1677 1678 void idGameSSDWindow::BeginLevel(int level) { 1679 1680 ResetLevelStats(); 1681 1682 gameStats.currentLevel = level; 1683 1684 StartGame(); 1685 } 1686 1687 /** 1688 * Continue game resets the players health 1689 */ 1690 void idGameSSDWindow::ContinueGame() { 1691 gameStats.health = 100; 1692 1693 StartGame(); 1694 } 1695 1696 void idGameSSDWindow::LevelComplete() { 1697 1698 gameStats.prebonusscore = gameStats.score; 1699 1700 // Add the bonuses 1701 int accuracy; 1702 if( !gameStats.levelStats.shotCount ) { 1703 accuracy = 0; 1704 } else { 1705 accuracy = (int)( ( (float)gameStats.levelStats.hitCount / (float)gameStats.levelStats.shotCount ) * 100.0f ); 1706 } 1707 int accuracyPoints = Max( 0, accuracy - 50 ) * 20; 1708 1709 gui->SetStateString("player_accuracy_score", va("%i", accuracyPoints)); 1710 1711 gameStats.score += accuracyPoints; 1712 1713 int saveAccuracy; 1714 int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts; 1715 if( !totalAst ) { 1716 saveAccuracy = 0; 1717 } else { 1718 saveAccuracy = (int)( ( (float)gameStats.levelStats.savedAstronauts / (float)totalAst ) * 100.0f ); 1719 } 1720 accuracyPoints = Max( 0, saveAccuracy - 50 ) * 20; 1721 1722 gui->SetStateString("save_accuracy_score", va("%i", accuracyPoints)); 1723 1724 gameStats.score += accuracyPoints; 1725 1726 1727 1728 StopSuperBlaster(); 1729 1730 gameStats.nextLevel++; 1731 1732 if(gameStats.nextLevel >= levelCount) { 1733 //Have they beaten the game 1734 GameComplete(); 1735 } else { 1736 1737 //Make sure we don't go above the levelcount 1738 //min(gameStats.nextLevel, levelCount-1); 1739 1740 StopGame(); 1741 gui->HandleNamedEvent("levelComplete"); 1742 } 1743 } 1744 1745 void idGameSSDWindow::GameComplete() { 1746 StopGame(); 1747 gui->HandleNamedEvent("gameComplete"); 1748 } 1749 1750 1751 void idGameSSDWindow::UpdateGame() { 1752 1753 //Check to see if and functions where called by the gui 1754 if(beginLevel == true) { 1755 beginLevel = false; 1756 BeginLevel(gameStats.nextLevel); 1757 } 1758 if(resetGame == true) { 1759 resetGame = false; 1760 ResetGameStats(); 1761 } 1762 if(continueGame == true) { 1763 continueGame = false; 1764 ContinueGame(); 1765 } 1766 if(refreshGuiData == true) { 1767 refreshGuiData = false; 1768 RefreshGuiData(); 1769 } 1770 1771 if(gameStats.gameRunning) { 1772 1773 //We assume an upate every 16 milliseconds 1774 ssdTime += 16; 1775 1776 if(superBlasterTimeout && ssdTime > superBlasterTimeout) { 1777 StopSuperBlaster(); 1778 } 1779 1780 //Find if we are targeting and enemy 1781 idVec2 cursor; 1782 //GetCursor(cursor); 1783 cursor.x = gui->CursorX(); 1784 cursor.y = gui->CursorY(); 1785 gameStats.levelStats.targetEnt = EntityHitTest(cursor); 1786 1787 //Update from back to front 1788 for(int i = entities.Num()-1; i >= 0; i--) { 1789 entities[i]->Update(); 1790 } 1791 1792 CheckForHits(); 1793 1794 //Delete entities that need to be deleted 1795 for(int i = entities.Num()-1; i >= 0; i--) { 1796 if(entities[i]->destroyed) { 1797 SSDEntity* ent = entities[i]; 1798 ent->DestroyEntity(); 1799 entities.RemoveIndex(i); 1800 } 1801 } 1802 1803 //Check if we can spawn an asteroid 1804 SpawnAsteroid(); 1805 1806 //Check if we should spawn an astronaut 1807 SpawnAstronaut(); 1808 1809 //Check if we should spawn an asteroid 1810 SpawnPowerup(); 1811 } 1812 } 1813 1814 void idGameSSDWindow::CheckForHits() { 1815 1816 //See if the entity has gotten close enough 1817 for(int i = 0; i < entities.Num(); i++) { 1818 SSDEntity* ent = entities[i]; 1819 if(ent->position.z <= Z_NEAR) { 1820 1821 if(!ent->noPlayerDamage) { 1822 1823 //Is the object still in the screen 1824 idVec3 entPos = ent->position; 1825 entPos.z = 0; 1826 1827 idBounds entBounds(entPos); 1828 entBounds.ExpandSelf(ent->hitRadius); 1829 1830 if(screenBounds.IntersectsBounds(entBounds)) { 1831 1832 ent->OnStrikePlayer(); 1833 1834 //The entity hit the player figure out what is was and act appropriately 1835 if(ent->type == SSD_ENTITY_ASTEROID) { 1836 AsteroidStruckPlayer(static_cast<SSDAsteroid*>(ent)); 1837 } else if(ent->type == SSD_ENTITY_ASTRONAUT) { 1838 AstronautStruckPlayer(static_cast<SSDAstronaut*>(ent)); 1839 } 1840 } else { 1841 //Tag for removal later in the frame 1842 ent->destroyed = true; 1843 } 1844 } 1845 } 1846 } 1847 } 1848 1849 void idGameSSDWindow::ZOrderEntities() { 1850 //Z-Order the entities 1851 //Using a simple sorting method 1852 for (int i = entities.Num()-1; i >= 0; i--) { 1853 bool flipped = false; 1854 for (int j = 0; j<i ; j++) { 1855 if (entities[j]->position.z > entities[j+1]->position.z) { 1856 SSDEntity* ent = entities[j]; 1857 entities[j] = entities[j+1]; 1858 entities[j+1] = ent; 1859 flipped = true; 1860 } 1861 } 1862 if (!flipped) { 1863 //Jump out because it is sorted 1864 break; 1865 } 1866 } 1867 } 1868 1869 void idGameSSDWindow::SpawnAsteroid() { 1870 1871 int currentTime = ssdTime; 1872 1873 if(currentTime < gameStats.levelStats.nextAsteroidSpawnTime) { 1874 //Not time yet 1875 return; 1876 } 1877 1878 //Lets spawn it 1879 idVec3 startPosition; 1880 1881 float spawnBuffer = levelData[gameStats.currentLevel].spawnBuffer*2.0f; 1882 startPosition.x = random.RandomInt(V_WIDTH+spawnBuffer)-((V_WIDTH/2.0f)+spawnBuffer); 1883 startPosition.y = random.RandomInt(V_HEIGHT+spawnBuffer)-((V_HEIGHT/2.0f)+spawnBuffer); 1884 startPosition.z = ENTITY_START_DIST; 1885 1886 float speed = random.RandomInt(asteroidData[gameStats.currentLevel].speedMax - asteroidData[gameStats.currentLevel].speedMin) + asteroidData[gameStats.currentLevel].speedMin; 1887 float size = random.RandomInt(asteroidData[gameStats.currentLevel].sizeMax - asteroidData[gameStats.currentLevel].sizeMin) + asteroidData[gameStats.currentLevel].sizeMin; 1888 float rotate = (random.RandomFloat() * (asteroidData[gameStats.currentLevel].rotateMax - asteroidData[gameStats.currentLevel].rotateMin)) + asteroidData[gameStats.currentLevel].rotateMin; 1889 1890 SSDAsteroid* asteroid = SSDAsteroid::GetNewAsteroid(this, startPosition, idVec2(size, size), speed, rotate, asteroidData[gameStats.currentLevel].asteroidHealth); 1891 entities.Append(asteroid); 1892 1893 gameStats.levelStats.nextAsteroidSpawnTime = currentTime + random.RandomInt(asteroidData[gameStats.currentLevel].spawnMax - asteroidData[gameStats.currentLevel].spawnMin) + asteroidData[gameStats.currentLevel].spawnMin; 1894 } 1895 1896 void idGameSSDWindow::FireWeapon(int key) { 1897 1898 idVec2 cursorWorld = GetCursorWorld(); 1899 idVec2 cursor; 1900 //GetCursor(cursor); 1901 cursor.x = gui->CursorX(); 1902 cursor.y = gui->CursorY(); 1903 1904 if(key == K_MOUSE1) { 1905 1906 gameStats.levelStats.shotCount++; 1907 1908 if(gameStats.levelStats.targetEnt) { 1909 //Aim the projectile from the bottom of the screen directly at the ent 1910 //SSDProjectile* newProj = new (TAG_OLD_UI) SSDProjectile(this, idVec3(320,0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size); 1911 SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size); 1912 entities.Append(newProj); 1913 //newProj = SSDProjectile::GetNewProjectile(this, idVec3(-320,-0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size); 1914 //entities.Append(newProj); 1915 1916 //We hit something 1917 gameStats.levelStats.hitCount++; 1918 1919 gameStats.levelStats.targetEnt->OnHit(key); 1920 1921 if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTEROID) { 1922 HitAsteroid(static_cast<SSDAsteroid*>(gameStats.levelStats.targetEnt), key); 1923 } else if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) { 1924 HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key); 1925 } 1926 } else { 1927 ////Aim the projectile at the cursor position all the way to the far clipping 1928 //SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/2.0f), weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size); 1929 1930 //Aim the projectile so it crosses the cursor 1/4 of screen 1931 idVec3 vec = idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/8.0f); 1932 vec *= 8; 1933 SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), vec, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size); 1934 entities.Append(newProj); 1935 1936 } 1937 1938 1939 //Play the blaster sound 1940 PlaySound("arcade_blaster"); 1941 1942 } /*else if (key == K_MOUSE2) { 1943 if(gameStats.levelStats.targetEnt) { 1944 if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) { 1945 HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key); 1946 } 1947 } 1948 }*/ 1949 } 1950 1951 SSDEntity* idGameSSDWindow::EntityHitTest(const idVec2& pt) { 1952 1953 for(int i = 0; i < entities.Num(); i++) { 1954 //Since we ZOrder the entities every frame we can stop at the first entity we hit. 1955 //ToDo: Make sure this assumption is true 1956 if(entities[i]->HitTest(pt)) { 1957 return entities[i]; 1958 } 1959 } 1960 return NULL; 1961 } 1962 1963 void idGameSSDWindow::HitAsteroid(SSDAsteroid* asteroid, int key) { 1964 1965 1966 1967 asteroid->health -= weaponData[gameStats.currentWeapon].damage; 1968 1969 if(asteroid->health <= 0) { 1970 1971 //The asteroid has been destroyed 1972 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid); 1973 entities.Append(explosion); 1974 PlaySound("arcade_explode"); 1975 1976 AddScore(asteroid, asteroidData[gameStats.currentLevel].asteroidPoints); 1977 1978 //Don't let the player hit it anymore because 1979 asteroid->noHit = true; 1980 1981 gameStats.levelStats.destroyedAsteroids++; 1982 //if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) { 1983 // LevelComplete(); 1984 //} 1985 1986 } else { 1987 //This was a damage hit so create a real small quick explosion 1988 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, asteroid, false, false); 1989 entities.Append(explosion); 1990 } 1991 } 1992 1993 void idGameSSDWindow::AsteroidStruckPlayer(SSDAsteroid* asteroid) { 1994 1995 asteroid->noPlayerDamage = true; 1996 asteroid->noHit = true; 1997 1998 AddDamage(asteroidData[gameStats.currentLevel].asteroidDamage); 1999 2000 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid); 2001 entities.Append(explosion); 2002 PlaySound("arcade_explode"); 2003 } 2004 2005 void idGameSSDWindow::AddScore(SSDEntity* ent, int points) { 2006 2007 SSDPoints* pointsEnt; 2008 2009 if(points > 0) { 2010 pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(0,1,0,1)); 2011 } else { 2012 pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(1,0,0,1)); 2013 } 2014 entities.Append(pointsEnt); 2015 2016 gameStats.score += points; 2017 gui->SetStateString( "player_score", va("%i", gameStats.score ) ); 2018 } 2019 2020 void idGameSSDWindow::AddDamage(int damage) { 2021 gameStats.health -= damage; 2022 gui->SetStateString( "player_health", va("%i", gameStats.health ) ); 2023 2024 gui->HandleNamedEvent( "playerDamage" ); 2025 2026 if(gameStats.health <= 0) { 2027 //The player is dead 2028 GameOver(); 2029 } 2030 } 2031 2032 void idGameSSDWindow::AddHealth(int health) { 2033 gameStats.health += health; 2034 gameStats.health = Min( 100, gameStats.health ); 2035 } 2036 2037 2038 void idGameSSDWindow::OnNuke() { 2039 2040 gui->HandleNamedEvent("nuke"); 2041 2042 //Destory All Asteroids 2043 for(int i = 0 ; i < entities.Num(); i++) { 2044 2045 if(entities[i]->type == SSD_ENTITY_ASTEROID) { 2046 2047 //The asteroid has been destroyed 2048 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, entities[i]->position, entities[i]->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, entities[i]); 2049 entities.Append(explosion); 2050 2051 AddScore(entities[i], asteroidData[gameStats.currentLevel].asteroidPoints); 2052 2053 //Don't let the player hit it anymore because 2054 entities[i]->noHit = true; 2055 2056 gameStats.levelStats.destroyedAsteroids++; 2057 } 2058 } 2059 PlaySound("arcade_explode"); 2060 2061 //Check to see if a nuke ends the level 2062 /*if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) { 2063 LevelComplete(); 2064 2065 }*/ 2066 } 2067 2068 void idGameSSDWindow::OnRescueAll() { 2069 2070 gui->HandleNamedEvent("rescueAll"); 2071 2072 //Rescue All Astronauts 2073 for(int i = 0 ; i < entities.Num(); i++) { 2074 2075 if(entities[i]->type == SSD_ENTITY_ASTRONAUT) { 2076 2077 AstronautStruckPlayer((SSDAstronaut*)entities[i]); 2078 } 2079 } 2080 } 2081 2082 void idGameSSDWindow::OnSuperBlaster() { 2083 2084 StartSuperBlaster(); 2085 } 2086 2087 2088 2089 void idGameSSDWindow::RefreshGuiData() { 2090 2091 2092 gui->SetStateString("nextLevel", va("%i", gameStats.nextLevel+1)); 2093 gui->SetStateString("currentLevel", va("%i", gameStats.currentLevel+1)); 2094 2095 float accuracy; 2096 if(!gameStats.levelStats.shotCount) { 2097 accuracy = 0; 2098 } else { 2099 accuracy = ((float)gameStats.levelStats.hitCount/(float)gameStats.levelStats.shotCount)*100.0f; 2100 } 2101 gui->SetStateString( "player_accuracy", va("%d%%", (int)accuracy)); 2102 2103 float saveAccuracy; 2104 int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts; 2105 2106 if(!totalAst) { 2107 saveAccuracy = 0; 2108 } else { 2109 saveAccuracy = ((float)gameStats.levelStats.savedAstronauts/(float)totalAst)*100.0f; 2110 } 2111 gui->SetStateString( "save_accuracy", va("%d%%", (int)saveAccuracy)); 2112 2113 2114 2115 2116 if(gameStats.levelStats.targetEnt) { 2117 int dist = (gameStats.levelStats.targetEnt->position.z/100.0f); 2118 dist *= 100; 2119 gui->SetStateString("target_info", va("%i meters", dist)); 2120 } else { 2121 gui->SetStateString("target_info", "No Target"); 2122 } 2123 2124 gui->SetStateString( "player_health", va("%i", gameStats.health ) ); 2125 gui->SetStateString( "player_score", va("%i", gameStats.score ) ); 2126 gui->SetStateString( "player_prebonusscore", va("%i", gameStats.prebonusscore ) ); 2127 gui->SetStateString( "level_complete", va("%i/%i", gameStats.levelStats.savedAstronauts, levelData[gameStats.currentLevel].needToWin )); 2128 2129 2130 if(superBlasterTimeout) { 2131 float timeRemaining = (superBlasterTimeout - ssdTime)/1000.0f; 2132 gui->SetStateString("super_blaster_time", va("%.2f", timeRemaining)); 2133 } 2134 } 2135 2136 idVec2 idGameSSDWindow::GetCursorWorld() { 2137 2138 idVec2 cursor; 2139 //GetCursor(cursor); 2140 cursor.x = gui->CursorX(); 2141 cursor.y = gui->CursorY(); 2142 cursor.x = cursor.x - 0.5f * V_WIDTH; 2143 cursor.y = -(cursor.y - 0.5f * V_HEIGHT); 2144 return cursor; 2145 } 2146 2147 void idGameSSDWindow::SpawnAstronaut() { 2148 2149 int currentTime = ssdTime; 2150 2151 if(currentTime < gameStats.levelStats.nextAstronautSpawnTime) { 2152 //Not time yet 2153 return; 2154 } 2155 2156 //Lets spawn it 2157 idVec3 startPosition; 2158 2159 startPosition.x = random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f); 2160 startPosition.y = random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f); 2161 startPosition.z = ENTITY_START_DIST; 2162 2163 float speed = random.RandomInt(astronautData[gameStats.currentLevel].speedMax - astronautData[gameStats.currentLevel].speedMin) + astronautData[gameStats.currentLevel].speedMin; 2164 float rotate = (random.RandomFloat() * (astronautData[gameStats.currentLevel].rotateMax - astronautData[gameStats.currentLevel].rotateMin)) + astronautData[gameStats.currentLevel].rotateMin; 2165 2166 SSDAstronaut* astronaut = SSDAstronaut::GetNewAstronaut(this, startPosition, speed, rotate, astronautData[gameStats.currentLevel].health); 2167 entities.Append(astronaut); 2168 2169 gameStats.levelStats.nextAstronautSpawnTime = currentTime + random.RandomInt(astronautData[gameStats.currentLevel].spawnMax - astronautData[gameStats.currentLevel].spawnMin) + astronautData[gameStats.currentLevel].spawnMin; 2170 } 2171 2172 void idGameSSDWindow::HitAstronaut(SSDAstronaut* astronaut, int key) { 2173 2174 2175 if(key == K_MOUSE1) { 2176 astronaut->health -= weaponData[gameStats.currentWeapon].damage; 2177 2178 if(astronaut->health <= 0) { 2179 2180 gameStats.levelStats.killedAstronauts++; 2181 2182 //The astronaut has been destroyed 2183 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, astronaut); 2184 entities.Append(explosion); 2185 PlaySound("arcade_explode"); 2186 2187 //Add the penalty for killing the astronaut 2188 AddScore(astronaut, astronautData[gameStats.currentLevel].penalty); 2189 2190 //Don't let the player hit it anymore 2191 astronaut->noHit = true; 2192 } else { 2193 //This was a damage hit so create a real small quick explosion 2194 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, astronaut, false, false); 2195 entities.Append(explosion); 2196 } 2197 } 2198 } 2199 2200 void idGameSSDWindow::AstronautStruckPlayer(SSDAstronaut* astronaut) { 2201 2202 gameStats.levelStats.savedAstronauts++; 2203 2204 astronaut->noPlayerDamage = true; 2205 astronaut->noHit = true; 2206 2207 //We are saving an astronaut 2208 SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_TELEPORT, astronaut); 2209 entities.Append(explosion); 2210 PlaySound("arcade_capture"); 2211 2212 //Give the player points for saving the astronaut 2213 AddScore(astronaut, astronautData[gameStats.currentLevel].points); 2214 2215 if(gameStats.levelStats.savedAstronauts >= levelData[gameStats.currentLevel].needToWin) { 2216 LevelComplete(); 2217 } 2218 2219 } 2220 2221 void idGameSSDWindow::SpawnPowerup() { 2222 2223 int currentTime = ssdTime; 2224 2225 if(currentTime < gameStats.levelStats.nextPowerupSpawnTime) { 2226 //Not time yet 2227 return; 2228 } 2229 2230 float speed = random.RandomInt(powerupData[gameStats.currentLevel].speedMax - powerupData[gameStats.currentLevel].speedMin) + powerupData[gameStats.currentLevel].speedMin; 2231 float rotate = (random.RandomFloat() * (powerupData[gameStats.currentLevel].rotateMax - powerupData[gameStats.currentLevel].rotateMin)) + powerupData[gameStats.currentLevel].rotateMin; 2232 2233 SSDPowerup* powerup = SSDPowerup::GetNewPowerup(this, speed, rotate); 2234 entities.Append(powerup); 2235 2236 gameStats.levelStats.nextPowerupSpawnTime = currentTime + random.RandomInt(powerupData[gameStats.currentLevel].spawnMax - powerupData[gameStats.currentLevel].spawnMin) + powerupData[gameStats.currentLevel].spawnMin; 2237 2238 } 2239 2240 void idGameSSDWindow::StartSuperBlaster() { 2241 2242 gui->HandleNamedEvent("startSuperBlaster"); 2243 gameStats.currentWeapon = 1; 2244 superBlasterTimeout = ssdTime + 10000; 2245 2246 } 2247 void idGameSSDWindow::StopSuperBlaster() { 2248 gui->HandleNamedEvent("stopSuperBlaster"); 2249 gameStats.currentWeapon = 0; 2250 superBlasterTimeout = 0; 2251 2252 } 2253 2254 SSDEntity* idGameSSDWindow::GetSpecificEntity(int type, int id) { 2255 SSDEntity* ent = NULL; 2256 switch(type) { 2257 case SSD_ENTITY_ASTEROID: 2258 ent = SSDAsteroid::GetSpecificAsteroid(id); 2259 break; 2260 case SSD_ENTITY_ASTRONAUT: 2261 ent = SSDAstronaut::GetSpecificAstronaut(id); 2262 break; 2263 case SSD_ENTITY_EXPLOSION: 2264 ent = SSDExplosion::GetSpecificExplosion(id); 2265 break; 2266 case SSD_ENTITY_POINTS: 2267 ent = SSDPoints::GetSpecificPoints(id); 2268 break; 2269 case SSD_ENTITY_PROJECTILE: 2270 ent = SSDProjectile::GetSpecificProjectile(id); 2271 break; 2272 case SSD_ENTITY_POWERUP: 2273 ent = SSDPowerup::GetSpecificPowerup(id); 2274 break; 2275 } 2276 return ent; 2277 } 2278 2279 #define MAX_SOUND_CHANNEL 8 2280 2281 void idGameSSDWindow::PlaySound(const char* sound) { 2282 2283 common->SW()->PlayShaderDirectly(sound, currentSound); 2284 2285 currentSound++; 2286 if(currentSound >= MAX_SOUND_CHANNEL) { 2287 currentSound = 0; 2288 } 2289 }