/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). Doom 3 Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 Source Code. If not, see . 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. 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. =========================================================================== */ #include "sys/platform.h" #include "framework/Session_local.h" #include "sound/sound.h" #include "ui/DeviceContext.h" #include "ui/Window.h" #include "ui/UserInterfaceLocal.h" #include "ui/GameBearShootWindow.h" #define BEAR_GRAVITY 240 #define BEAR_SIZE 24.f #define BEAR_SHRINK_TIME 2000.f #define MAX_WINDFORCE 100.f idCVar bearTurretAngle( "bearTurretAngle", "0", CVAR_FLOAT, "" ); idCVar bearTurretForce( "bearTurretForce", "200", CVAR_FLOAT, "" ); /* ***************************************************************************** * BSEntity **************************************************************************** */ BSEntity::BSEntity(idGameBearShootWindow* _game) { game = _game; visible = true; entColor = colorWhite; materialName = ""; material = NULL; width = height = 8; rotation = 0.f; rotationSpeed = 0.f; fadeIn = false; fadeOut = false; position.Zero(); velocity.Zero(); } BSEntity::~BSEntity() { } /* ====================== BSEntity::WriteToSaveGame ====================== */ void BSEntity::WriteToSaveGame( idFile *savefile ) { game->WriteSaveGameString( materialName, savefile ); savefile->Write( &width, sizeof(width) ); savefile->Write( &height, sizeof(height) ); savefile->Write( &visible, sizeof(visible) ); savefile->Write( &entColor, sizeof(entColor) ); savefile->Write( &position, sizeof(position) ); savefile->Write( &rotation, sizeof(rotation) ); savefile->Write( &rotationSpeed, sizeof(rotationSpeed) ); savefile->Write( &velocity, sizeof(velocity) ); savefile->Write( &fadeIn, sizeof(fadeIn) ); savefile->Write( &fadeOut, sizeof(fadeOut) ); } /* ====================== BSEntity::ReadFromSaveGame ====================== */ void BSEntity::ReadFromSaveGame( idFile *savefile, idGameBearShootWindow* _game ) { game = _game; game->ReadSaveGameString( materialName, savefile ); SetMaterial( materialName ); savefile->Read( &width, sizeof(width) ); savefile->Read( &height, sizeof(height) ); savefile->Read( &visible, sizeof(visible) ); savefile->Read( &entColor, sizeof(entColor) ); savefile->Read( &position, sizeof(position) ); savefile->Read( &rotation, sizeof(rotation) ); savefile->Read( &rotationSpeed, sizeof(rotationSpeed) ); savefile->Read( &velocity, sizeof(velocity) ); savefile->Read( &fadeIn, sizeof(fadeIn) ); savefile->Read( &fadeOut, sizeof(fadeOut) ); } /* ====================== BSEntity::SetMaterial ====================== */ void BSEntity::SetMaterial(const char* name) { materialName = name; material = declManager->FindMaterial( name ); material->SetSort( SS_GUI ); } /* ====================== BSEntity::SetSize ====================== */ void BSEntity::SetSize( float _width, float _height ) { width = _width; height = _height; } /* ====================== BSEntity::SetVisible ====================== */ void BSEntity::SetVisible( bool isVisible ) { visible = isVisible; } /* ====================== BSEntity::Update ====================== */ void BSEntity::Update( float timeslice ) { if ( !visible ) { return; } // Fades if ( fadeIn && entColor.w < 1.f ) { entColor.w += 1 * timeslice; if ( entColor.w >= 1.f ) { entColor.w = 1.f; fadeIn = false; } } if ( fadeOut && entColor.w > 0.f ) { entColor.w -= 1 * timeslice; if ( entColor.w <= 0.f ) { entColor.w = 0.f; fadeOut = false; } } // Move the entity position += velocity * timeslice; // Rotate Entity rotation += rotationSpeed * timeslice; } /* ====================== BSEntity::Draw ====================== */ void BSEntity::Draw(idDeviceContext *dc) { if ( visible ) { dc->DrawMaterialRotated( position.x, position.y, width, height, material, entColor, 1.0f, 1.0f, DEG2RAD(rotation) ); } } /* ***************************************************************************** * idGameBearShootWindow **************************************************************************** */ idGameBearShootWindow::idGameBearShootWindow(idDeviceContext *d, idUserInterfaceLocal *g) : idWindow(d, g) { dc = d; gui = g; CommonInit(); } idGameBearShootWindow::idGameBearShootWindow(idUserInterfaceLocal *g) : idWindow(g) { gui = g; CommonInit(); } idGameBearShootWindow::~idGameBearShootWindow() { entities.DeleteContents(true); } /* ============================= idGameBearShootWindow::WriteToSaveGame ============================= */ void idGameBearShootWindow::WriteToSaveGame( idFile *savefile ) { idWindow::WriteToSaveGame( savefile ); gamerunning.WriteToSaveGame( savefile ); onFire.WriteToSaveGame( savefile ); onContinue.WriteToSaveGame( savefile ); onNewGame.WriteToSaveGame( savefile ); savefile->Write( &timeSlice, sizeof(timeSlice) ); savefile->Write( &timeRemaining, sizeof(timeRemaining) ); savefile->Write( &gameOver, sizeof(gameOver) ); savefile->Write( ¤tLevel, sizeof(currentLevel) ); savefile->Write( &goalsHit, sizeof(goalsHit) ); savefile->Write( &updateScore, sizeof(updateScore) ); savefile->Write( &bearHitTarget, sizeof(bearHitTarget) ); savefile->Write( &bearScale, sizeof(bearScale) ); savefile->Write( &bearIsShrinking, sizeof(bearIsShrinking) ); savefile->Write( &bearShrinkStartTime, sizeof(bearShrinkStartTime) ); savefile->Write( &turretAngle, sizeof(turretAngle) ); savefile->Write( &turretForce, sizeof(turretForce) ); savefile->Write( &windForce, sizeof(windForce) ); savefile->Write( &windUpdateTime, sizeof(windUpdateTime) ); int numberOfEnts = entities.Num(); savefile->Write( &numberOfEnts, sizeof(numberOfEnts) ); for ( int i=0; iWriteToSaveGame( savefile ); } int index; index = entities.FindIndex( turret ); savefile->Write( &index, sizeof(index) ); index = entities.FindIndex( bear ); savefile->Write( &index, sizeof(index) ); index = entities.FindIndex( helicopter ); savefile->Write( &index, sizeof(index) ); index = entities.FindIndex( goal ); savefile->Write( &index, sizeof(index) ); index = entities.FindIndex( wind ); savefile->Write( &index, sizeof(index) ); index = entities.FindIndex( gunblast ); savefile->Write( &index, sizeof(index) ); } /* ============================= idGameBearShootWindow::ReadFromSaveGame ============================= */ void idGameBearShootWindow::ReadFromSaveGame( idFile *savefile ) { idWindow::ReadFromSaveGame( savefile ); // Remove all existing entities entities.DeleteContents(true); gamerunning.ReadFromSaveGame( savefile ); onFire.ReadFromSaveGame( savefile ); onContinue.ReadFromSaveGame( savefile ); onNewGame.ReadFromSaveGame( savefile ); savefile->Read( &timeSlice, sizeof(timeSlice) ); savefile->Read( &timeRemaining, sizeof(timeRemaining) ); savefile->Read( &gameOver, sizeof(gameOver) ); savefile->Read( ¤tLevel, sizeof(currentLevel) ); savefile->Read( &goalsHit, sizeof(goalsHit) ); savefile->Read( &updateScore, sizeof(updateScore) ); savefile->Read( &bearHitTarget, sizeof(bearHitTarget) ); savefile->Read( &bearScale, sizeof(bearScale) ); savefile->Read( &bearIsShrinking, sizeof(bearIsShrinking) ); savefile->Read( &bearShrinkStartTime, sizeof(bearShrinkStartTime) ); savefile->Read( &turretAngle, sizeof(turretAngle) ); savefile->Read( &turretForce, sizeof(turretForce) ); savefile->Read( &windForce, sizeof(windForce) ); savefile->Read( &windUpdateTime, sizeof(windUpdateTime) ); int numberOfEnts; savefile->Read( &numberOfEnts, sizeof(numberOfEnts) ); for ( int i=0; iReadFromSaveGame( savefile, this ); entities.Append( ent ); } int index; savefile->Read( &index, sizeof(index) ); turret = entities[index]; savefile->Read( &index, sizeof(index) ); bear = entities[index]; savefile->Read( &index, sizeof(index) ); helicopter = entities[index]; savefile->Read( &index, sizeof(index) ); goal = entities[index]; savefile->Read( &index, sizeof(index) ); wind = entities[index]; savefile->Read( &index, sizeof(index) ); gunblast = entities[index]; } /* ============================= idGameBearShootWindow::ResetGameState ============================= */ void idGameBearShootWindow::ResetGameState() { gamerunning = false; gameOver = false; onFire = false; onContinue = false; onNewGame = false; // Game moves forward 16 milliseconds every frame timeSlice = 0.016f; timeRemaining = 60.f; goalsHit = 0; updateScore = false; bearHitTarget = false; currentLevel = 1; turretAngle = 0.f; turretForce = 200.f; windForce = 0.f; windUpdateTime = 0; bearIsShrinking = false; bearShrinkStartTime = 0; bearScale = 1.f; } /* ============================= idGameBearShootWindow::CommonInit ============================= */ void idGameBearShootWindow::CommonInit() { BSEntity * ent; // Precache sounds declManager->FindSound( "arcade_beargroan" ); declManager->FindSound( "arcade_sargeshoot" ); declManager->FindSound( "arcade_balloonpop" ); declManager->FindSound( "arcade_levelcomplete1" ); // Precache dynamically used materials declManager->FindMaterial( "game/bearshoot/helicopter_broken" ); declManager->FindMaterial( "game/bearshoot/goal_dead" ); declManager->FindMaterial( "game/bearshoot/gun_blast" ); ResetGameState(); ent = new BSEntity( this ); turret = ent; ent->SetMaterial( "game/bearshoot/turret" ); ent->SetSize( 272, 144 ); ent->position.x = -44; ent->position.y = 260; entities.Append( ent ); ent = new BSEntity( this ); ent->SetMaterial( "game/bearshoot/turret_base" ); ent->SetSize( 144, 160 ); ent->position.x = 16; ent->position.y = 280; entities.Append( ent ); ent = new BSEntity( this ); bear = ent; ent->SetMaterial( "game/bearshoot/bear" ); ent->SetSize( BEAR_SIZE, BEAR_SIZE ); ent->SetVisible( false ); ent->position.x = 0; ent->position.y = 0; entities.Append( ent ); ent = new BSEntity( this ); helicopter = ent; ent->SetMaterial( "game/bearshoot/helicopter" ); ent->SetSize( 64, 64 ); ent->position.x = 550; ent->position.y = 100; entities.Append( ent ); ent = new BSEntity( this ); goal = ent; ent->SetMaterial( "game/bearshoot/goal" ); ent->SetSize( 64, 64 ); ent->position.x = 550; ent->position.y = 164; entities.Append( ent ); ent = new BSEntity( this ); wind = ent; ent->SetMaterial( "game/bearshoot/wind" ); ent->SetSize( 100, 40 ); ent->position.x = 500; ent->position.y = 430; entities.Append( ent ); ent = new BSEntity( this ); gunblast = ent; ent->SetMaterial( "game/bearshoot/gun_blast" ); ent->SetSize( 64, 64 ); ent->SetVisible( false ); entities.Append( ent ); } /* ============================= idGameBearShootWindow::HandleEvent ============================= */ const char *idGameBearShootWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) { int key = event->evValue; // need to call this to allow proper focus and capturing on embedded children const char *ret = idWindow::HandleEvent(event, updateVisuals); if ( event->evType == SE_KEY ) { if ( !event->evValue2 ) { return ret; } if ( key == K_MOUSE1) { // Mouse was clicked } else { return ret; } } return ret; } /* ============================= idGameBearShootWindow::ParseInternalVar ============================= */ bool idGameBearShootWindow::ParseInternalVar(const char *_name, idParser *src) { if ( idStr::Icmp(_name, "gamerunning") == 0 ) { gamerunning = src->ParseBool(); return true; } if ( idStr::Icmp(_name, "onFire") == 0 ) { onFire = src->ParseBool(); return true; } if ( idStr::Icmp(_name, "onContinue") == 0 ) { onContinue = src->ParseBool(); return true; } if ( idStr::Icmp(_name, "onNewGame") == 0 ) { onNewGame = src->ParseBool(); return true; } return idWindow::ParseInternalVar(_name, src); } /* ============================= idGameBearShootWindow::GetWinVarByName ============================= */ idWinVar *idGameBearShootWindow::GetWinVarByName(const char *_name, bool winLookup, drawWin_t** owner) { idWinVar *retVar = NULL; if ( idStr::Icmp(_name, "gamerunning") == 0 ) { retVar = &gamerunning; } else if ( idStr::Icmp(_name, "onFire") == 0 ) { retVar = &onFire; } else if ( idStr::Icmp(_name, "onContinue") == 0 ) { retVar = &onContinue; } else if ( idStr::Icmp(_name, "onNewGame") == 0 ) { retVar = &onNewGame; } if(retVar) { return retVar; } return idWindow::GetWinVarByName(_name, winLookup, owner); } /* ============================= idGameBearShootWindow::PostParse ============================= */ void idGameBearShootWindow::PostParse() { idWindow::PostParse(); } /* ============================= idGameBearShootWindow::Draw ============================= */ void idGameBearShootWindow::Draw(int time, float x, float y) { int i; //Update the game every frame before drawing UpdateGame(); for( i = entities.Num()-1; i >= 0; i-- ) { entities[i]->Draw(dc); } } /* ============================= idGameBearShootWindow::UpdateTurret ============================= */ void idGameBearShootWindow::UpdateTurret() { idVec2 pt; idVec2 turretOrig; idVec2 right; float dot, angle; pt.x = gui->CursorX(); pt.y = gui->CursorY(); turretOrig.Set( 80.f, 348.f ); pt = pt - turretOrig; pt.NormalizeFast(); right.x = 1.f; right.y = 0.f; dot = pt * right; angle = RAD2DEG( acosf( dot ) ); turretAngle = idMath::ClampFloat( 0.f, 90.f, angle ); } /* ============================= idGameBearShootWindow::UpdateBear ============================= */ void idGameBearShootWindow::UpdateBear() { int time = gui->GetTime(); bool startShrink = false; // Apply gravity bear->velocity.y += BEAR_GRAVITY * timeSlice; // Apply wind bear->velocity.x += windForce * timeSlice; // Check for collisions if ( !bearHitTarget && !gameOver ) { idVec2 bearCenter; bool collision = false; bearCenter.x = bear->position.x + bear->width/2; bearCenter.y = bear->position.y + bear->height/2; if ( bearCenter.x > (helicopter->position.x + 16) && bearCenter.x < (helicopter->position.x + helicopter->width - 29) ) { if ( bearCenter.y > (helicopter->position.y + 12) && bearCenter.y < (helicopter->position.y + helicopter->height - 7) ) { collision = true; } } if ( collision ) { // balloons pop and bear tumbles to ground helicopter->SetMaterial( "game/bearshoot/helicopter_broken" ); helicopter->velocity.y = 230.f; goal->velocity.y = 230.f; session->sw->PlayShaderDirectly( "arcade_balloonpop" ); bear->SetVisible( false ); if ( bear->velocity.x > 0 ) { bear->velocity.x *= -1.f; } bear->velocity *= 0.666f; bearHitTarget = true; updateScore = true; startShrink = true; } } // Check for ground collision if ( bear->position.y > 380 ) { bear->position.y = 380; if ( bear->velocity.Length() < 25 ) { bear->velocity.Zero(); } else { startShrink = true; bear->velocity.y *= -1.f; bear->velocity *= 0.5f; if ( bearScale ) { session->sw->PlayShaderDirectly( "arcade_balloonpop" ); } } } // Bear rotation is based on velocity float angle; idVec2 dir; dir = bear->velocity; dir.NormalizeFast(); angle = RAD2DEG( atan2( dir.x, dir.y ) ); bear->rotation = angle - 90; // Update Bear scale if ( bear->position.x > 650 ) { startShrink = true; } if ( !bearIsShrinking && bearScale && startShrink ) { bearShrinkStartTime = time; bearIsShrinking = true; } if ( bearIsShrinking ) { if ( bearHitTarget ) { bearScale = 1 - ( (float)(time - bearShrinkStartTime) / BEAR_SHRINK_TIME ); } else { bearScale = 1 - ( (float)(time - bearShrinkStartTime) / 750 ); } bearScale *= BEAR_SIZE; bear->SetSize( bearScale, bearScale ); if ( bearScale < 0 ) { gui->HandleNamedEvent( "EnableFireButton" ); bearIsShrinking = false; bearScale = 0.f; if ( bearHitTarget ) { goal->SetMaterial( "game/bearshoot/goal" ); goal->position.x = 550; goal->position.y = 164; goal->velocity.Zero(); goal->velocity.y = (currentLevel-1) * 30; goal->entColor.w = 0.f; goal->fadeIn = true; goal->fadeOut = false; helicopter->SetVisible( true ); helicopter->SetMaterial( "game/bearshoot/helicopter" ); helicopter->position.x = 550; helicopter->position.y = 100; helicopter->velocity.Zero(); helicopter->velocity.y = goal->velocity.y; helicopter->entColor.w = 0.f; helicopter->fadeIn = true; helicopter->fadeOut = false; } } } } /* ============================= idGameBearShootWindow::UpdateHelicopter ============================= */ void idGameBearShootWindow::UpdateHelicopter() { if ( bearHitTarget && bearIsShrinking ) { if ( helicopter->velocity.y != 0 && helicopter->position.y > 264 ) { helicopter->velocity.y = 0; goal->velocity.y = 0; helicopter->SetVisible( false ); goal->SetMaterial( "game/bearshoot/goal_dead" ); session->sw->PlayShaderDirectly( "arcade_beargroan", 1 ); helicopter->fadeOut = true; goal->fadeOut = true; } } else if ( currentLevel > 1 ) { int height = helicopter->position.y; float speed = (currentLevel-1) * 30; if ( height > 240 ) { helicopter->velocity.y = -speed; goal->velocity.y = -speed; } else if ( height < 30 ) { helicopter->velocity.y = speed; goal->velocity.y = speed; } } } /* ============================= idGameBearShootWindow::UpdateButtons ============================= */ void idGameBearShootWindow::UpdateButtons() { if ( onFire ) { idVec2 vec; gui->HandleNamedEvent( "DisableFireButton" ); session->sw->PlayShaderDirectly( "arcade_sargeshoot" ); bear->SetVisible( true ); bearScale = 1.f; bear->SetSize( BEAR_SIZE, BEAR_SIZE ); vec.x = idMath::Cos( DEG2RAD(turretAngle) ); vec.x += ( 1 - vec.x ) * 0.18f; vec.y = -idMath::Sin( DEG2RAD(turretAngle) ); turretForce = bearTurretForce.GetFloat(); bear->position.x = 80 + ( 96 * vec.x ); bear->position.y = 334 + ( 96 * vec.y ); bear->velocity.x = vec.x * turretForce; bear->velocity.y = vec.y * turretForce; gunblast->position.x = 55 + ( 96 * vec.x ); gunblast->position.y = 310 + ( 100 * vec.y ); gunblast->SetVisible( true ); gunblast->entColor.w = 1.f; gunblast->rotation = turretAngle; gunblast->fadeOut = true; bearHitTarget = false; onFire = false; } } /* ============================= idGameBearShootWindow::UpdateScore ============================= */ void idGameBearShootWindow::UpdateScore() { if ( gameOver ) { gui->HandleNamedEvent( "GameOver" ); return; } goalsHit++; gui->SetStateString( "player_score", va("%i", goalsHit ) ); // Check for level progression if ( !(goalsHit % 5) ) { currentLevel++; gui->SetStateString( "current_level", va("%i", currentLevel ) ); session->sw->PlayShaderDirectly( "arcade_levelcomplete1", 3 ); timeRemaining += 30; } } /* ============================= idGameBearShootWindow::UpdateGame ============================= */ void idGameBearShootWindow::UpdateGame() { int i; if ( onNewGame ) { ResetGameState(); goal->position.x = 550; goal->position.y = 164; goal->velocity.Zero(); helicopter->position.x = 550; helicopter->position.y = 100; helicopter->velocity.Zero(); bear->SetVisible( false ); bearTurretAngle.SetFloat( 0.f ); bearTurretForce.SetFloat( 200.f ); gamerunning = true; } if ( onContinue ) { gameOver = false; timeRemaining = 60.f; onContinue = false; } if(gamerunning == true) { int current_time = gui->GetTime(); idRandom rnd( current_time ); // Check for button presses UpdateButtons(); if ( bear ) { UpdateBear(); } if ( helicopter && goal ) { UpdateHelicopter(); } // Update Wind if ( windUpdateTime < current_time ) { float scale; int width; windForce = rnd.CRandomFloat() * ( MAX_WINDFORCE * 0.75f ); if (windForce > 0) { windForce += ( MAX_WINDFORCE * 0.25f ); wind->rotation = 0; } else { windForce -= ( MAX_WINDFORCE * 0.25f ); wind->rotation = 180; } scale = 1.f - (( MAX_WINDFORCE - idMath::Fabs(windForce) ) / MAX_WINDFORCE); width = 100*scale; if ( windForce < 0 ) { wind->position.x = 500 - width + 1; } else { wind->position.x = 500; } wind->SetSize( width, 40 ); windUpdateTime = current_time + 7000 + rnd.RandomInt(5000); } // Update turret rotation angle if ( turret ) { turretAngle = bearTurretAngle.GetFloat(); turret->rotation = turretAngle; } for( i = 0; i < entities.Num(); i++ ) { entities[i]->Update( timeSlice ); } // Update countdown timer timeRemaining -= timeSlice; timeRemaining = idMath::ClampFloat( 0.f, 99999.f, timeRemaining ); gui->SetStateString( "time_remaining", va("%2.1f", timeRemaining ) ); if ( timeRemaining <= 0.f && !gameOver ) { gameOver = true; updateScore = true; } if ( updateScore ) { UpdateScore(); updateScore = false; } } }