# define OLC_PGE_APPLICATION
# define OLC_SOUNDWAVE
# define OLC_PGEX_TRANSFORMEDVIEW
# define AUDIO_LISTENER_IMPLEMENTATION
# define AUDIO_SOURCE_IMPLEMENTATION
# define OLC_PGEX_QUICKGUI
# define SPLASH_ENABLED
# ifdef SPLASH_ENABLED
# define OLC_PGEX_SPLASHSCREEN
# endif
# include "Scenario.h"
# include "TileManager.h"
# include "olcUTIL_Geometry2D.h"
# include "util.h"
# include "Level.h"
# include "Scenario.h"
# include "VirusAttack.h"
VirusAttack * game ;
std : : vector < std : : unique_ptr < Renderable > > IMAGES ;
std : : vector < std : : unique_ptr < Audio > > SOUNDS ;
std : : vector < std : : unique_ptr < Scenario > > SCENARIOS ;
VirusAttack : : VirusAttack ( )
{
// Name your application
sAppName = " Virus Attack " ;
game = this ;
}
void VirusAttack : : InitializeImages ( ) {
auto LoadImage = [ & ] ( Image img , std : : string filepath , bool filter = false , bool clamp = true ) {
IMAGES . emplace_back ( std : : make_unique < Renderable > ( ) ) ;
IMAGES [ img ] - > Load ( filepath , nullptr , filter , clamp ) ;
} ;
LoadImage ( TILE , " assets/tile.png " , false , false ) ;
LoadImage ( MINIMAP_HUD , " assets/minimap_hud.png " ) ;
LoadImage ( OUTLINE , " assets/outline.png " ) ;
IMAGES . emplace_back ( std : : make_unique < Renderable > ( ) ) ;
IMAGES [ MINIMAP_OUTLINE ] - > Create ( 64 , 64 ) ;
LoadImage ( VIRUS_IMG1 , " assets/unit.png " ) ;
LoadImage ( SELECTION_CIRCLE , " assets/selection_circle.png " ) ;
IMAGES . emplace_back ( std : : make_unique < Renderable > ( ) ) ;
IMAGES [ MATRIX ] - > Create ( 64 , 64 , false , false ) ;
IMAGES [ MATRIX ] - > Sprite ( ) - > SetSampleMode ( Sprite : : PERIODIC ) ;
LoadImage ( MEMORY_COLLECTION_POINT , " assets/memory_collection_point.png " ) ;
LoadImage ( LEFT_SHIFTER , " assets/left_shifter.png " ) ;
LoadImage ( RIGHT_SHIFTER , " assets/right_shifter.png " ) ;
LoadImage ( BIT_RESTORER , " assets/bit_restorer.png " ) ;
LoadImage ( MEMORY_SWAPPER , " assets/memory_swapper.png " ) ;
LoadImage ( CORRUPTER , " assets/corrupter.png " ) ;
LoadImage ( UNIT_ALLOCATOR , " assets/shell.png " ) ;
LoadImage ( RAM_BANK , " assets/ram_bank.png " ) ;
LoadImage ( RANGE_INDICATOR , " assets/range_indicator.png " ) ;
LoadImage ( DOWN_ARROW , " assets/down_arrow.png " ) ;
LoadImage ( RED_X , " assets/red_x.png " ) ;
LoadImage ( RLD , " assets/rld.png " ) ;
LoadImage ( PRC , " assets/prc.png " ) ;
LoadImage ( RNG , " assets/rng.png " ) ;
LoadImage ( SPD , " assets/spd.png " ) ;
LoadImage ( TARGETING_LINE , " assets/targetLine.png " ) ;
LoadImage ( ATTACKING_LINE , " assets/attackLine.png " , false , false ) ;
LoadImage ( RLD_ICON , " assets/rld_icon.png " ) ;
LoadImage ( PRC_ICON , " assets/prc_icon.png " ) ;
LoadImage ( RNG_ICON , " assets/rng_icon.png " ) ;
LoadImage ( SPD_ICON , " assets/spd_icon.png " ) ;
LoadImage ( RESOURCE , " assets/material.png " ) ;
LoadImage ( MEMORY_COLLECTION_POINT_HIGHLIGHT , " assets/memory_collection_point_highlight.png " ) ;
LoadImage ( MEMORY_GUARD , " assets/memoryguard.png " ) ;
LoadImage ( REFRESHER , " assets/refresher.png " ) ;
LoadImage ( TURRET , " assets/turret.png " ) ;
LoadImage ( PLATFORM , " assets/platform.png " ) ;
LoadImage ( GUARD_ICON , " assets/shieldIcon.png " ) ;
LoadImage ( GUIDE , " assets/guide.png " ) ;
LoadImage ( ROUND_BAR , " assets/round_bar.png " ) ;
LoadImage ( SEGMENT_BAR , " assets/segmentBar.png " , false , false ) ;
LoadImage ( HOODED_FIGURE , " assets/hooded_figure.png " ) ;
LoadImage ( SPOOK_HOODED_FIGURE , " assets/spook_hooded_figure.png " ) ;
LoadImage ( RESTART , " assets/restart.png " ) ;
LoadImage ( RESTART_HOVER , " assets/restartHover.png " ) ;
LoadImage ( SHIELD_BUBBLE , " assets/shieldbubble.png " ) ;
titleScreenText . Create ( 426 , 100 , false , true ) ;
SetDrawTarget ( titleScreenText . Sprite ( ) ) ;
Clear ( BLANK ) ;
float textScale = 3 ;
vf2d textSize = GetTextSizeProp ( " Virus Attack " ) * textScale ;
DrawShadowStringProp ( titleScreenText . Sprite ( ) - > Size ( ) / 2 - textSize / 2 , " Virus Attack " , WHITE , BLACK , { textScale , textScale } , textScale ) ;
SetDrawTarget ( nullptr ) ;
titleScreenText . Decal ( ) - > Update ( ) ;
textOrientationX = titleScreenText . Sprite ( ) - > width / 2 ;
textOrientationY = titleScreenText . Sprite ( ) - > height - 12 ;
}
void VirusAttack : : InitializeLevelData ( ) {
# pragma region Stage 1
{
//Stage 1 data.
LevelName stage = STAGE1 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . levelColor = DARK_GREEN ;
levelData [ stage ] . size = { 24 , 24 } ;
levelData [ stage ] . bgm = Sound : : GRAVITY ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 240 ;
levelData [ stage ] . player_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
levelData [ stage ] . enemy_starting_resources = { 0 , 0 , 0 , 0 , 0 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 128 , 128 } , true } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 128 , 128 } , true } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 320 , 320 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 2
{
//Stage 2 data.
LevelName stage = STAGE2 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 30 , 30 } ;
levelData [ stage ] . levelColor = DARK_GREEN ;
levelData [ stage ] . bgm = Sound : : GRAVITY ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 240 ;
levelData [ stage ] . player_starting_resources = { 50 , 30 , 40 , 30 , 55 } ;
levelData [ stage ] . enemy_starting_resources = { 0 , 0 , 0 , 0 , 0 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : _Platform , vf2d { 7 * 24 , 10 * 24 } , true } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 20 * 24 , 21 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 20 * 24 , 22 * 24 } , false } ) ;
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 22 * 24 , 24 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 22 * 24 , 23 * 24 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 3
{
//Stage 3 data.
LevelName stage = STAGE3 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 30 , 30 } ;
levelData [ stage ] . levelColor = DARK_GREEN ;
levelData [ stage ] . bgm = Sound : : GRAVITY ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 240 ;
levelData [ stage ] . player_starting_resources = { 100 , 40 , 60 , 40 , 100 } ;
levelData [ stage ] . enemy_starting_resources = { 0 , 0 , 0 , 0 , 0 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 3 * 24 , 6 * 24 } , true } ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
units . push_back ( { UnitType : : RightShifter , vf2d { 3 * 24 , 8 * 24 } , true } ) ;
}
units . push_back ( { UnitType : : LeftShifter , vf2d { 3 * 24 , 7 * 24 } , true } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 18 * 24 , 19 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 20 * 24 , 22 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 21 * 24 , 22 * 24 } , false } ) ;
for ( int i = 0 ; i < 8 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 20 * 24 , 17 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : _Platform , vf2d { 22 * 24 , 23 * 24 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 4
{
//Stage 4 data.
LevelName stage = STAGE4 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 36 , 36 } ;
levelData [ stage ] . levelColor = DARK_GREEN ;
levelData [ stage ] . bgm = Sound : : COSMOS ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 300 ;
levelData [ stage ] . player_starting_resources = { 3 , 0 , 0 , 0 , 0 } ;
levelData [ stage ] . enemy_starting_resources = { 3 , 0 , 0 , 0 , 0 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 4 * 24 } , true } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 4 * 24 , 6 * 24 } , true } ) ;
}
collectionPoints . push_back ( CPData { { 8 * 24 , 1 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 9 * 24 , 1 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 12 * 24 , 1 * 24 } , 0 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 15 * 24 , 1 * 24 } , 0 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 12 * 24 } , - PI / 2 , MemoryType : : RANGE } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 13 * 24 } , - PI / 2 , MemoryType : : ATKSPD } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 17 * 24 } , - PI / 2 , MemoryType : : MOVESPD } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 20 * 24 } , - PI / 2 , MemoryType : : RANGE } ) ;
}
}
# pragma endregion
# pragma region Stage 5
{
//Stage 5 data.
LevelName stage = STAGE5 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 48 , 48 } ;
levelData [ stage ] . levelColor = DARK_GREY ;
levelData [ stage ] . bgm = Sound : : BOSS1 ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 640 ;
levelData [ stage ] . player_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
levelData [ stage ] . enemy_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 4 * 24 } , true } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 4 * 24 , 6 * 24 } , true } ) ;
}
collectionPoints . push_back ( CPData { { 8 * 24 , 1 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 10 * 24 , 1 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 32 * 24 , 12 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 20 * 24 , 32 * 24 } , 0 , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { 9 * 24 , 1 * 24 } , 0 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 7 * 24 } , - PI / 2 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 16 * 24 , 16 * 24 } , 0 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 36 * 24 , 1 * 24 } , - PI / 2 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 3 * 24 } , - PI / 2 , MemoryType : : RANGE } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 6 * 24 } , - PI / 2 , MemoryType : : ATKSPD } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 11 * 24 } , - PI / 2 , MemoryType : : MOVESPD } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 22 * 24 } , - PI / 2 , MemoryType : : RANGE } ) ;
collectionPoints . push_back ( CPData { { 6 * 24 , 16 * 24 } , - PI / 2 , MemoryType : : ATKSPD } ) ;
collectionPoints . push_back ( CPData { { 1 * 24 , 32 * 24 } , - PI / 2 , MemoryType : : MOVESPD } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 4 ) * 24 } , PI / 2 , MemoryType : : RANGE } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 7 ) * 24 } , PI / 2 , MemoryType : : ATKSPD } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 12 ) * 24 } , PI / 2 , MemoryType : : MOVESPD } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 23 ) * 24 } , PI / 2 , MemoryType : : RANGE } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 6 ) * 24 , ( 48 - 17 ) * 24 } , PI / 2 , MemoryType : : ATKSPD } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 33 ) * 24 } , PI / 2 , MemoryType : : MOVESPD } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 8 ) * 24 , ( 48 - 2 ) * 24 } , PI , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 10 ) * 24 , ( 48 - 2 ) * 24 } , PI , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 32 ) * 24 , ( 48 - 13 ) * 24 } , PI , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 20 ) * 24 , ( 48 - 33 ) * 24 } , PI , MemoryType : : HEALTH } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 9 ) * 24 , ( 48 - 2 ) * 24 } , PI , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 1 ) * 24 , ( 48 - 8 ) * 24 } , PI / 2 , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 16 ) * 24 , ( 48 - 17 ) * 24 } , PI , MemoryType : : PROCEDURE } ) ;
collectionPoints . push_back ( CPData { { ( 48 - 36 ) * 24 , ( 48 - 2 ) * 24 } , PI / 2 , MemoryType : : PROCEDURE } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 44 * 24 , 44 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : Turret , vf2d { 42 * 24 , 42 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 42 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 42 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : Corrupter , vf2d { 42 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 42 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 45 * 24 , 41 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 44 * 24 , 44 * 24 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 6
{
//Stage 6 data.
LevelName stage = STAGE6 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 48 , 48 } ;
levelData [ stage ] . levelColor = DARK_GREY ;
levelData [ stage ] . bgm = Sound : : BOSS1 ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 640 ;
levelData [ stage ] . player_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
levelData [ stage ] . enemy_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 4 * 24 } , true } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 4 * 24 , 6 * 24 } , true } ) ;
}
std : : vector < vf2d > positions = {
{ { 8 , 1 } , { 10 , 1 } , { 32 , 12 } , { 20 , 32 } , { 9 , 1 } , { 1 , 7 } , { 16 , 16 }
, { 36 , 1 } , { 1 , 3 } , { 1 , 6 } , { 1 , 11 } , { 1 , 22 } , { 6 , 16 } , { 1 , 32 } }
} ;
std : : vector < MemoryType > types = {
{ MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : PROCEDURE ,
MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : RANGE ,
MemoryType : : ATKSPD , MemoryType : : MOVESPD , MemoryType : : RANGE , MemoryType : : ATKSPD , MemoryType : : MOVESPD , }
} ;
if ( positions . size ( ) ! = types . size ( ) ) {
throw ;
}
while ( positions . size ( ) > 0 ) {
int randomIndex = rand ( ) % positions . size ( ) ;
int randomIndex2 = rand ( ) % types . size ( ) ;
float finalDir = 0 ;
if ( positions [ randomIndex ] . x < levelData [ stage ] . size . x / 2 ) {
if ( positions [ randomIndex ] . y < positions [ randomIndex ] . x ) {
finalDir = 0 ;
} else {
finalDir = - PI / 2 ;
}
} else {
if ( positions [ randomIndex ] . y > positions [ randomIndex ] . x ) {
finalDir = PI ;
} else {
finalDir = PI / 2 ;
}
}
collectionPoints . push_back ( CPData { positions [ randomIndex ] * 24 , finalDir , types [ randomIndex2 ] } ) ;
collectionPoints . push_back ( CPData { ( levelData [ stage ] . size - positions [ randomIndex ] - vf2d { 1 , 1 } ) * 24 , float ( finalDir + PI ) , types [ randomIndex2 ] } ) ;
positions . erase ( positions . begin ( ) + randomIndex ) ;
types . erase ( types . begin ( ) + randomIndex2 ) ;
}
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 44 * 24 , 44 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : Refresher , vf2d { 2 * 24 , 42 * 24 } , false } ) ;
units . push_back ( { UnitType : : MemoryGuard , vf2d { 7 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 2 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 2 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : Corrupter , vf2d { 2 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 2 * 24 , 44 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 5 * 24 , 41 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 44 * 24 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 7
{
//Stage 7 data.
LevelName stage = STAGE7 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 64 , 64 } ;
levelData [ stage ] . levelColor = DARK_RED ;
levelData [ stage ] . bgm = Sound : : BOSS2 ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 960 ;
levelData [ stage ] . player_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
levelData [ stage ] . enemy_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 4 * 24 } , true } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 4 * 24 , 6 * 24 } , true } ) ;
}
std : : vector < vf2d > positions = {
{ { 8 , 1 } , { 10 , 1 } , { 32 , 12 } , { 20 , 32 } , { 9 , 1 } , { 1 , 7 } , { 16 , 16 }
, { 36 , 1 } , { 1 , 3 } , { 1 , 6 } , { 1 , 11 } , { 1 , 22 } , { 6 , 16 } , { 1 , 32 }
, { 14 , 16 } , { 27 , 29 } , { 14 , 12 } , { 7 , 36 } , { 16 , 30 } , { 22 , 19 } , { 39 , 40 } }
} ;
std : : vector < MemoryType > types = {
{ MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : PROCEDURE ,
MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : RANGE ,
MemoryType : : ATKSPD , MemoryType : : MOVESPD , MemoryType : : RANGE , MemoryType : : ATKSPD , MemoryType : : MOVESPD ,
MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : PROCEDURE ,
MemoryType : : PROCEDURE , MemoryType : : ATKSPD , MemoryType : : MOVESPD , MemoryType : : RANGE , }
} ;
if ( positions . size ( ) ! = types . size ( ) ) {
throw ;
}
while ( positions . size ( ) > 0 ) {
int randomIndex = rand ( ) % positions . size ( ) ;
int randomIndex2 = rand ( ) % types . size ( ) ;
float finalDir = 0 ;
if ( positions [ randomIndex ] . x < levelData [ stage ] . size . x / 2 ) {
if ( positions [ randomIndex ] . y < positions [ randomIndex ] . x ) {
finalDir = 0 ;
} else {
finalDir = - PI / 2 ;
}
} else {
if ( positions [ randomIndex ] . y > positions [ randomIndex ] . x ) {
finalDir = PI ;
} else {
finalDir = PI / 2 ;
}
}
collectionPoints . push_back ( CPData { positions [ randomIndex ] * 24 , finalDir , types [ randomIndex2 ] } ) ;
collectionPoints . push_back ( CPData { ( levelData [ stage ] . size - positions [ randomIndex ] - vf2d { 1 , 1 } ) * 24 , float ( finalDir + PI ) , types [ randomIndex2 ] } ) ;
positions . erase ( positions . begin ( ) + randomIndex ) ;
types . erase ( types . begin ( ) + randomIndex2 ) ;
}
units . push_back ( { UnitType : : Turret , vf2d { 52 * 24 , 52 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 52 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : LeftShifter , vf2d { 52 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : Corrupter , vf2d { 52 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 52 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 55 * 24 , 51 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 54 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 54 * 24 , 54 * 24 } , false } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 54 * 24 , 54 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : Turret , vf2d { 53 * 24 , 22 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 54 * 24 , 24 * 24 } , false } ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 54 * 24 , 25 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : RightShifter , vf2d { 53 * 24 , 24 * 24 } , false } ) ;
units . push_back ( { UnitType : : BitRestorer , vf2d { 54 * 24 , 25 * 24 } , false } ) ;
units . push_back ( { UnitType : : RightShifter , vf2d { 54 * 24 , 26 * 24 } , false } ) ;
}
}
# pragma endregion
# pragma region Stage 8
{
//Stage 8 data.
LevelName stage = STAGE8 ;
levelData [ stage ] . name = stage ;
levelData [ stage ] . cameraStart = { 96 , 96 } ;
levelData [ stage ] . worldZoom = { 1 , 1 } ;
levelData [ stage ] . size = { 64 , 64 } ;
levelData [ stage ] . levelColor = DARK_RED ;
levelData [ stage ] . bgm = Sound : : BOSS2 ;
levelData [ stage ] . scenarioIndex = int ( stage ) ;
levelData [ stage ] . availableMemory = 1280 ;
levelData [ stage ] . player_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
levelData [ stage ] . enemy_starting_resources = { 5 , 5 , 5 , 5 , 5 } ;
{
std : : vector < UnitData > & units = levelData [ stage ] . unitPlacement ;
std : : vector < CPData > & collectionPoints = levelData [ stage ] . cpPlacement ;
units . push_back ( { UnitType : : RAMBank , vf2d { 4 * 24 , 4 * 24 } , true } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 4 * 24 , 6 * 24 } , true } ) ;
}
std : : vector < vf2d > positions = {
{ { 8 , 1 } , { 10 , 1 } , { 32 , 12 } , { 20 , 32 } , { 9 , 1 } , { 1 , 7 } , { 16 , 16 }
, { 36 , 1 } , { 1 , 3 } , { 1 , 6 } , { 1 , 11 } , { 1 , 22 } , { 6 , 16 } , { 1 , 32 }
, { 14 , 16 } , { 27 , 29 } , { 14 , 12 } , { 7 , 36 } , { 16 , 30 } , { 22 , 19 } , { 39 , 40 } }
} ;
std : : vector < MemoryType > types = {
{ MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : PROCEDURE ,
MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : PROCEDURE , MemoryType : : RANGE ,
MemoryType : : ATKSPD , MemoryType : : MOVESPD , MemoryType : : RANGE , MemoryType : : ATKSPD , MemoryType : : MOVESPD ,
MemoryType : : HEALTH , MemoryType : : HEALTH , MemoryType : : PROCEDURE ,
MemoryType : : PROCEDURE , MemoryType : : ATKSPD , MemoryType : : MOVESPD , MemoryType : : RANGE , }
} ;
if ( positions . size ( ) ! = types . size ( ) ) {
throw ;
}
while ( positions . size ( ) > 0 ) {
int randomIndex = rand ( ) % positions . size ( ) ;
int randomIndex2 = rand ( ) % types . size ( ) ;
float finalDir = 0 ;
if ( positions [ randomIndex ] . x < levelData [ stage ] . size . x / 2 ) {
if ( positions [ randomIndex ] . y < positions [ randomIndex ] . x ) {
finalDir = 0 ;
} else {
finalDir = - PI / 2 ;
}
} else {
if ( positions [ randomIndex ] . y > positions [ randomIndex ] . x ) {
finalDir = PI ;
} else {
finalDir = PI / 2 ;
}
}
collectionPoints . push_back ( CPData { positions [ randomIndex ] * 24 , finalDir , types [ randomIndex2 ] } ) ;
collectionPoints . push_back ( CPData { ( levelData [ stage ] . size - positions [ randomIndex ] - vf2d { 1 , 1 } ) * 24 , float ( finalDir + PI ) , types [ randomIndex2 ] } ) ;
positions . erase ( positions . begin ( ) + randomIndex ) ;
types . erase ( types . begin ( ) + randomIndex2 ) ;
}
for ( int i = 0 ; i < 2 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 53 * 24 , 53 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : Refresher , vf2d { 56 * 24 , 56 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 54 * 24 , 54 * 24 } , false } ) ;
for ( int i = 0 ; i < 5 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 39 * 24 , 35 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : Refresher , vf2d { 43 * 24 , 52 * 24 } , false } ) ;
units . push_back ( { UnitType : : Turret , vf2d { 44 * 24 , 52 * 24 } , false } ) ;
units . push_back ( { UnitType : : MemoryGuard , vf2d { 40 * 24 , 35 * 24 } , false } ) ;
units . push_back ( { UnitType : : RAMBank , vf2d { 40 * 24 , 36 * 24 } , false } ) ;
units . push_back ( { UnitType : : Turret , vf2d { 37 * 24 , 57 * 24 } , false } ) ;
units . push_back ( { UnitType : : Turret , vf2d { 42 * 24 , 57 * 24 } , false } ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
units . push_back ( { UnitType : : MemoryAllocator , vf2d { 10 * 24 , 53 * 24 } , false } ) ;
}
units . push_back ( { UnitType : : RAMBank , vf2d { 10 * 24 , 54 * 24 } , false } ) ;
units . push_back ( { UnitType : : Turret , vf2d { 11 * 24 , 52 * 24 } , false } ) ;
}
}
# pragma endregion
}
bool VirusAttack : : OnUserCreate ( ) {
srand ( time ( NULL ) ) ;
currentBackCol = newCol = colorChangeOptions [ rand ( ) % colorChangeOptions . size ( ) ] ;
SetPixelMode ( Pixel : : MASK ) ;
gametv . Initialise ( GetScreenSize ( ) ) ;
InitializeImages ( ) ;
unitCreationBox . Initialize ( " Hello world, this is a test of the textbox system. \n Maybe even with some newline characters snuck in there. " ,
{ } ) ;
unitCreationBox . SetVisible ( false ) ;
testBox . Initialize ( " Hello world, this is a test of the textbox system. \n Maybe even with some newline characters snuck in there. " , { } ) ;
testBox . SetVisible ( false ) ;
memoryAllocatorBox . Initialize ( CONSTANT : : MEMORY_ALLOCATOR_BOX_DISPLAY_STRING , { } , CONSTANT : : MEMORY_ALLOCATOR_BOX_HEADER_STRING ) ;
memoryAllocatorBox . SetVisible ( false ) ;
platformCreationBox . SetVisible ( false ) ;
restartBox . SetVisible ( false ) ;
completedBox . SetVisible ( false ) ;
creditsBox . SetVisible ( false ) ;
attackingLineModified . Create ( IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > width , IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > height , false , false ) ;
AL . AudioSystemInit ( ) ;
InitializeSounds ( ) ;
InitializeGUIs ( ) ;
InitializeScenarios ( ) ;
InitializeLevelData ( ) ;
LoadLevel ( STAGE1 ) ;
levelToLoad = STAGE1 ;
return true ;
}
void VirusAttack : : LoadLevel ( LevelName level ) {
Level & selectedLevel = levelData [ level ] ;
currentLevel = & selectedLevel ;
currentScenario = currentLevel - > scenarioIndex ;
WORLD_SIZE = selectedLevel . size ;
gametv . SetWorldScale ( selectedLevel . worldZoom ) ;
gametv . SetWorldOffset ( selectedLevel . cameraStart - vf2d ( GetScreenSize ( ) ) / 2.f / gametv . GetWorldScale ( ) ) ;
if ( bgm = = nullptr ) {
bgm = SOUNDS [ int ( selectedLevel . bgm ) ] . get ( ) ;
bgm_handle = bgm - > PlayCentered ( 1 , 1 , true ) ;
} else
if ( bgm ! = SOUNDS [ int ( selectedLevel . bgm ) ] . get ( ) ) {
bgm - > Stop ( ) ;
bgm = SOUNDS [ int ( selectedLevel . bgm ) ] . get ( ) ;
bgm_handle = bgm - > PlayCentered ( 1 , 1 , true ) ;
}
player_resources = selectedLevel . player_starting_resources ;
enemy_resources = selectedLevel . enemy_starting_resources ;
TileManager : : visibleTiles . clear ( ) ;
std : : for_each ( units . begin ( ) , units . end ( ) , [ & ] ( auto & u ) {
u - > OnDeath ( SOUNDS ) ;
} ) ;
units . clear ( ) ;
collectionPoints . clear ( ) ;
for ( auto & u : selectedLevel . unitPlacement ) {
# define TranslateUnit(type) \
case UnitType : : type : { \
units . push_back ( std : : make_shared < type > ( this , u . pos , IMAGES , u . friendly ) ) ; \
} break ;
switch ( u . type ) {
TranslateUnit ( LeftShifter )
TranslateUnit ( RightShifter )
TranslateUnit ( BitRestorer )
TranslateUnit ( MemorySwapper )
TranslateUnit ( Corrupter )
TranslateUnit ( MemoryAllocator )
TranslateUnit ( RAMBank )
TranslateUnit ( _Platform )
TranslateUnit ( MemoryGuard )
TranslateUnit ( Refresher )
TranslateUnit ( Turret )
default : {
std : : cout < < " Could not load unit type " < < int ( u . type ) < < " ! " < < std : : endl ;
throw ;
}
}
}
for ( auto & cp : selectedLevel . cpPlacement ) {
collectionPoints . push_back ( std : : make_shared < CollectionPoint > ( this , cp . pos , cp . rot , * IMAGES [ MEMORY_COLLECTION_POINT ] , cp . type ) ) ;
}
randomBackgroundOffset = { util : : random ( 128 ) , util : : random ( 128 ) } ;
objective = " " ;
SCENARIOS [ currentScenario ] - > _Start ( ) ;
}
void VirusAttack : : InitializeGUIs ( ) {
restartButton = new QuickGUI : : TransparentImageButton ( restartManager , * IMAGES [ RESTART ] , * IMAGES [ RESTART_HOVER ] , { 1 , 1 } , { float ( ScreenWidth ( ) - 32 ) , 12.f } , { 28 , 28 } ) ;
unitCreationList . colNormal = olc : : DARK_GREEN ;
unitCreationList . colHover = olc : : GREEN ;
unitCreationList . colClick = olc : : YELLOW ;
unitCreationList . colDisable = olc : : DARK_GREY ;
unitCreationList . colBorder = olc : : YELLOW ;
unitCreationList . colText = olc : : WHITE ;
platformCreationList . CopyThemeFrom ( unitCreationList ) ;
leftShifterButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ LEFT_SHIFTER ] , { 0.5 , 0.5 } , { 16.f + 32 * 0 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
rightShifterButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ RIGHT_SHIFTER ] , { 0.5 , 0.5 } , { 16.f + 32 * 1 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
bitRestorerButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ BIT_RESTORER ] , { 0.5 , 0.5 } , { 16.f + 32 * 2 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
memorySwapperButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ MEMORY_SWAPPER ] , { 0.5 , 0.5 } , { 16.f + 32 * 3 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
corrupterButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ CORRUPTER ] , { 0.5 , 0.5 } , { 16.f + 32 * 4 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
platformButton = new QuickGUI : : ImageButton ( unitCreationList , * IMAGES [ PLATFORM ] , { 0.25 , 0.25 } , { 16.f + 32 * 5 , float ( ScreenHeight ( ) - 48 ) } , { 20 , 20 } ) ;
ramBankButton = new QuickGUI : : ImageButton ( platformCreationList , * IMAGES [ RAM_BANK ] , { 0.125 , 0.125 } , { float ( ScreenWidth ( ) - 48 ) , 48.f + 32 * 0 } , { 20 , 20 } ) ;
refresherButton = new QuickGUI : : ImageButton ( platformCreationList , * IMAGES [ REFRESHER ] , { 0.25 , 0.25 } , { float ( ScreenWidth ( ) - 48 ) , 48.f + 32 * 1 } , { 20 , 20 } ) ;
turretButton = new QuickGUI : : ImageButton ( platformCreationList , * IMAGES [ TURRET ] , { 0.25 , 0.25 } , { float ( ScreenWidth ( ) - 48 ) , 48.f + 32 * 2 } , { 20 , 20 } ) ;
memoryGuardButton = new QuickGUI : : ImageButton ( platformCreationList , * IMAGES [ MEMORY_GUARD ] , { 0.25 , 0.25 } , { float ( ScreenWidth ( ) - 48 ) , 48.f + 32 * 3 } , { 20 , 20 } ) ;
unitCreationList . DisplayAllControls ( false ) ;
platformCreationList . DisplayAllControls ( false ) ;
campaignStartButton = new QuickGUI : : TransparentButton ( mainMenu , " Start Campaign " , { float ( ScreenWidth ( ) / 2 ) - 120.f , 80 + 47.5f * 1 + 10 } , { 240 , 24 } , CONSTANT : : INCREASE_VALUE_COLOR ) ;
audioToggleButton = new QuickGUI : : TransparentButton ( mainMenu , " Audio: On " , { float ( ScreenWidth ( ) / 2 ) - 120.f , 80 + 47.5f * 2 + 10 } , { 240 , 24 } , CONSTANT : : INCREASE_VALUE_COLOR ) ;
difficultyToggleButton = new QuickGUI : : TransparentButton ( mainMenu , " Difficulty: Normal " , { float ( ScreenWidth ( ) / 2 ) - 120.f , 80 + 47.5f * 3 + 10 } , { 240 , 24 } , CONSTANT : : INCREASE_VALUE_COLOR ) ;
//creditsButton=new QuickGUI::TransparentButton(mainMenu,"Credits",{float(ScreenWidth()/2)-120.f,80+47.5f*3+10},{240,24},CONSTANT::INCREASE_VALUE_COLOR);
exitGameButton = new QuickGUI : : TransparentButton ( mainMenu , " Exit Game " , { float ( ScreenWidth ( ) / 2 ) - 120.f , 80 + 47.5f * 4 + 10 } , { 240 , 24 } , CONSTANT : : INCREASE_VALUE_COLOR ) ;
}
void VirusAttack : : InitializeScenarios ( ) {
SCENARIOS . emplace_back ( std : : make_unique < Stage1 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage2 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage3 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage4 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage5 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage6 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage7 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
SCENARIOS . emplace_back ( std : : make_unique < Stage8 > ( units , IMAGES , SOUNDS , objective , gametv , flags ) ) ;
}
void VirusAttack : : InitializeSounds ( ) {
int soundIndex = 0 ;
auto LoadSound = [ & ] ( Sound : : Sound sound , std : : string soundFilename ) {
SOUNDS . emplace_back ( std : : make_unique < Audio > ( ) ) ;
SOUNDS [ int ( sound ) ] - > AL = & AL ;
SOUNDS [ int ( sound ) ] - > LoadAudioSample ( soundIndex , std : : string ( " ./assets/ " + soundFilename ) . c_str ( ) ) ;
soundIndex + + ;
} ;
LoadSound ( Sound : : HUM , " machine2.wav " ) ;
LoadSound ( Sound : : GRAVITY , " gravity.mp3 " ) ;
LoadSound ( Sound : : COSMOS , " cosmos.mp3 " ) ;
LoadSound ( Sound : : BOSS1 , " boss1.mp3 " ) ;
LoadSound ( Sound : : BOSS2 , " boss2.mp3 " ) ;
LoadSound ( Sound : : VOICEOVER , " voice.mp3 " ) ;
LoadSound ( Sound : : PING , " ping.mp3 " ) ;
LoadSound ( Sound : : ALARM , " alarm.mp3 " ) ;
LoadSound ( Sound : : SWITCH , " switch.mp3 " ) ;
LoadSound ( Sound : : HIT1 , " hit1.mp3 " ) ;
LoadSound ( Sound : : HIT2 , " hit2.mp3 " ) ;
LoadSound ( Sound : : HIT3 , " hit3.mp3 " ) ;
LoadSound ( Sound : : BUTTONSELECT , " buttonselect.mp3 " ) ;
LoadSound ( Sound : : SMALLBUILD , " smallbuild.mp3 " ) ;
LoadSound ( Sound : : BIGBUILD , " bigbuild.mp3 " ) ;
LoadSound ( Sound : : HEAL , " heal.mp3 " ) ;
LoadSound ( Sound : : REFRESHER , " refresher.mp3 " ) ;
LoadSound ( Sound : : TURRET , " turret.mp3 " ) ;
LoadSound ( Sound : : MEMORY_GUARD , " memoryguard.mp3 " ) ;
LoadSound ( Sound : : SPAWN , " spawn.mp3 " ) ;
LoadSound ( Sound : : DEAD1 , " dead1.mp3 " ) ;
LoadSound ( Sound : : DEAD2 , " dead2.mp3 " ) ;
LoadSound ( Sound : : DEAD3 , " dead3.mp3 " ) ;
LoadSound ( Sound : : WIND , " wind.mp3 " ) ;
}
bool VirusAttack : : UnitCreationClickHandled ( ) {
# define CheckClick(UnitClass,Button,Validator) \
if ( Button - > bPressed ) { \
for ( auto & u : units ) { \
if ( u - > IsSelected ( ) & & u - > Validator ( ) & & CanAfford ( player_resources , UnitClass : : resourceCost ) ) { \
std : : shared_ptr < UnitClass > buildUnit = std : : make_shared < UnitClass > ( this , u - > GetPos ( ) , IMAGES , u - > IsFriendly ( ) ) ; \
u - > SetBuildUnit ( CONSTANT : : UNIT_BUILD_TIME , std : : move ( buildUnit ) , SOUNDS ) ; \
ExpendResources ( player_resources , UnitClass : : resourceCost ) ; \
CalculateUsedMemory ( ) ; \
} \
} \
SOUNDS [ Sound : : BUTTONSELECT ] - > PlayCentered ( ) ; \
return true ; \
}
CheckClick ( LeftShifter , leftShifterButton , IsAllocator )
CheckClick ( RightShifter , rightShifterButton , IsAllocator )
CheckClick ( BitRestorer , bitRestorerButton , IsAllocator )
CheckClick ( MemorySwapper , memorySwapperButton , IsAllocator )
CheckClick ( BitRestorer , bitRestorerButton , IsAllocator )
CheckClick ( Corrupter , corrupterButton , IsAllocator )
CheckClick ( _Platform , platformButton , IsAllocator )
CheckClick ( RAMBank , ramBankButton , IsPlatform )
CheckClick ( Refresher , refresherButton , IsPlatform )
CheckClick ( Turret , turretButton , IsPlatform )
CheckClick ( MemoryGuard , memoryGuardButton , IsPlatform )
return false ;
}
# define EnableAndHoverCheck(UnitClass,Button,box,allowed) \
Button - > Enable ( CanAfford ( player_resources , UnitClass : : resourceCost ) & & allowed ) ; \
if ( ! allowed ) { Button - > bVisible = false ; } \
if ( Button - > bHover ) { \
box . Initialize ( UnitClass : : unitDescription , GetMousePos ( ) , UnitClass : : unitName , nullptr , { 120 , 36 } , nullptr , UnitClass : : resourceCost ) ; \
hovering = true ; \
if ( CanAfford ( player_resources , UnitClass : : resourceCost ) ) { \
box . SetBackgroundColor ( CONSTANT : : MESSAGE_BOX_DEFAULT_BACKCOL ) ; \
} else { \
box . SetBackgroundColor ( VERY_DARK_GREY / 2 ) ; \
} \
}
void VirusAttack : : UpdateUnitCreationListGUI ( bool allocatorSelected ) {
unitCreationList . DisplayAllControls ( allocatorSelected ) ;
bool hovering = false ;
EnableAndHoverCheck ( LeftShifter , leftShifterButton , unitCreationBox , true )
EnableAndHoverCheck ( RightShifter , rightShifterButton , unitCreationBox , true )
EnableAndHoverCheck ( BitRestorer , bitRestorerButton , unitCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( MemorySwapper , memorySwapperButton , unitCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( BitRestorer , bitRestorerButton , unitCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( Corrupter , corrupterButton , unitCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( _Platform , platformButton , unitCreationBox , ! flags . limitedBuildOptions )
if ( ! hovering ) {
unitCreationBox . SetVisible ( false ) ;
}
unitCreationList . Update ( this ) ;
}
void VirusAttack : : UpdatePlatformCreationListGUI ( bool platformSelected ) {
platformCreationList . DisplayAllControls ( platformSelected ) ;
bool hovering = false ;
EnableAndHoverCheck ( RAMBank , ramBankButton , platformCreationBox , true )
EnableAndHoverCheck ( Refresher , refresherButton , platformCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( Turret , turretButton , platformCreationBox , ! flags . limitedBuildOptions )
EnableAndHoverCheck ( MemoryGuard , memoryGuardButton , platformCreationBox , ! flags . limitedBuildOptions )
if ( ! hovering ) {
platformCreationBox . SetVisible ( false ) ;
}
platformCreationList . Update ( this ) ;
}
void VirusAttack : : HandleDraggingSelection ( ) {
auto NotClickingOnMinimap = [ & ] ( ) { return ! ( GetMouseX ( ) > = ScreenWidth ( ) - 64 & & GetMouseY ( ) > = ScreenHeight ( ) - 64 ) ; } ;
if ( GetMouse ( 0 ) . bPressed ) {
if ( NotClickingOnMinimap ( ) ) {
for ( auto & u : units ) {
if ( u - > ClickHandled ( gametv , player_resources , units , IMAGES ) ) {
goto skipLeftClick ; //Break out early because this instance reported it handled a click for us.
}
}
if ( UnitCreationClickHandled ( ) ) {
goto skipLeftClick ;
}
for ( auto & u : units ) {
u - > Deselect ( ) ;
}
if ( startingDragPos = = CONSTANT : : UNSELECTED ) {
startingDragPos = GetWorldMousePos ( ) ;
}
}
}
skipLeftClick :
if ( GetMouse ( 0 ) . bReleased & & startingDragPos ! = CONSTANT : : UNSELECTED ) {
vf2d endDragPos = GetWorldMousePos ( ) ;
if ( endDragPos . x < startingDragPos . x ) { std : : swap ( startingDragPos . x , endDragPos . x ) ; }
if ( endDragPos . y < startingDragPos . y ) { std : : swap ( startingDragPos . y , endDragPos . y ) ; }
geom2d : : rect < float > selectionRegion ( startingDragPos , endDragPos - startingDragPos ) ;
for ( auto & u : units ) {
if ( u - > IsFriendly ( ) ) {
if ( geom2d : : overlaps ( selectionRegion , geom2d : : circle < float > ( u - > GetPos ( ) , u - > GetUnitSize ( ) . x / 2 ) ) ) {
u - > Select ( ) ;
}
}
}
startingDragPos = CONSTANT : : UNSELECTED ;
}
}
vf2d VirusAttack : : GetWorldMousePos ( ) {
return gametv . ScreenToWorld ( GetMousePos ( ) ) ;
}
void VirusAttack : : DrawSelectionRectangle ( ) {
if ( startingDragPos ! = CONSTANT : : UNSELECTED ) {
gametv . FillRectDecal ( startingDragPos , GetWorldMousePos ( ) - startingDragPos , { 255 , 255 , 0 , 128 } ) ;
}
}
void VirusAttack : : HandleRightClickMove ( ) {
if ( GetMouse ( 1 ) . bHeld ) {
bool selectedTarget = false ;
if ( GetMouseX ( ) > = ScreenWidth ( ) - 64 & & GetMouseY ( ) > = ScreenHeight ( ) - 64 ) { //Clicked on Minimap.
for ( auto & u : units ) {
if ( u - > IsFriendly ( ) & & u - > IsSelected ( ) & & u - > CanMove ( ) ) {
vf2d minimapTL = GetScreenSize ( ) - vf2d { 64 , 64 } ;
vf2d minimapCenterClick = vf2d ( GetMousePos ( ) - minimapTL ) / 64 * WORLD_SIZE * CONSTANT : : TILE_SIZE - vf2d ( GetScreenSize ( ) ) / gametv . GetWorldScale ( ) / 2.f + vf2d ( GetScreenSize ( ) / 2.f ) / gametv . GetWorldScale ( ) ;
u - > SetTargetLocation ( minimapCenterClick ) ;
}
}
goto targetFound ;
}
for ( auto & u : units ) {
if ( geom2d : : overlaps ( geom2d : : circle < float > ( u - > GetPos ( ) , u - > GetUnitSize ( ) . x / 2 ) , GetWorldMousePos ( ) ) ) {
for ( auto & u2 : units ) {
if ( & u ! = & u2 ) {
if ( ! u - > IsFriendly ( ) & & u2 - > IsFriendly ( ) & & u2 - > IsSelected ( ) & & u2 - > CanInteractWithEnemies ( ) ) {
u2 - > SetTargetUnit ( u ) ;
} else
if ( u - > IsFriendly ( ) & & u2 - > IsFriendly ( ) & & u2 - > IsSelected ( ) & & u2 - > CanInteractWithAllies ( ) ) {
u2 - > SetTargetUnit ( u ) ;
}
}
}
selectedTarget = true ;
break ;
}
}
if ( ! selectedTarget ) {
for ( auto & u : units ) {
if ( u - > IsFriendly ( ) & & u - > IsSelected ( ) & & u - > CanMove ( ) ) {
//First see if we can attach to a collection point.
for ( auto & cp : collectionPoints ) {
geom2d : : rect < float > cpRect = geom2d : : rect < float > ( { cp - > pos - cp - > img . Sprite ( ) - > Size ( ) / 2 , cp - > img . Sprite ( ) - > Size ( ) } ) ;
if ( geom2d : : overlaps ( cpRect , GetWorldMousePos ( ) ) ) {
if ( cp - > attachedUnit . expired ( ) ) {
u - > SetTargetCollectionPoint ( cp , u ) ;
goto targetFound ; //We found a target, so now we can just leave.
}
}
}
//Okay, nothing to do here. Simply move to the selected position.
u - > SetTargetLocation ( GetWorldMousePos ( ) ) ;
}
}
}
targetFound :
int a ;
}
}
void VirusAttack : : CollisionChecking ( std : : shared_ptr < Unit > u , std : : shared_ptr < Unit > u2 ) {
if ( u - > GetPos ( ) . x < 0 ) {
u - > SetPos ( { 0 , u - > GetPos ( ) . y } ) ;
}
if ( u - > GetPos ( ) . x > WORLD_SIZE . x * CONSTANT : : TILE_SIZE . x ) {
u - > SetPos ( { float ( WORLD_SIZE . x * CONSTANT : : TILE_SIZE . x ) , u - > GetPos ( ) . y } ) ;
}
if ( u - > GetPos ( ) . y < 0 ) {
u - > SetPos ( { u - > GetPos ( ) . y , 0 } ) ;
}
if ( u - > GetPos ( ) . y > WORLD_SIZE . y * CONSTANT : : TILE_SIZE . y ) {
u - > SetPos ( { u - > GetPos ( ) . x , float ( WORLD_SIZE . y * CONSTANT : : TILE_SIZE . y ) } ) ;
}
if ( u ! = u2 & & geom2d : : overlaps ( geom2d : : circle < float > ( u - > GetPos ( ) , u - > GetUnitSize ( ) . x / 2 ) , geom2d : : circle < float > ( u2 - > GetPos ( ) , u2 - > GetUnitSize ( ) . x / 2 ) ) ) {
geom2d : : line < float > collisionLine ( u - > GetPos ( ) , u2 - > GetPos ( ) + vf2d { 0.001 , 0.001 } ) ;
float maxDist = u - > GetUnitSize ( ) . x / 2 + u2 - > GetUnitSize ( ) . x / 2 ;
float dist = maxDist - collisionLine . length ( ) ;
vf2d dir = collisionLine . vector ( ) . norm ( ) ;
if ( u - > IsMoveable ( ) | | ( ! u - > IsMoveable ( ) & & ! u2 - > IsMoveable ( ) ) ) {
u - > SetPos ( u - > GetPos ( ) - dir * dist / 2 ) ;
}
if ( u2 - > IsMoveable ( ) | | ( ! u - > IsMoveable ( ) & & ! u2 - > IsMoveable ( ) ) ) {
u2 - > SetPos ( u2 - > GetPos ( ) + dir * ( dist ) / 2 ) ;
}
}
}
void VirusAttack : : IdentifyClosestTarget ( std : : weak_ptr < Unit > & closestUnit , float & closestDist , std : : shared_ptr < Unit > u , std : : shared_ptr < Unit > u2 ) {
if ( u = = u2 ) return ;
bool canInteract ;
canInteract =
( u - > IsFriendly ( ) & & u - > CanInteractWithEnemies ( ) & & ! u2 - > IsFriendly ( ) ) | |
( u - > IsFriendly ( ) & & u - > CanInteractWithAllies ( ) & & u2 - > IsFriendly ( ) & & u - > AutoAcquiresFriendlyTargets ( ) ) | |
( ! u - > IsFriendly ( ) & & u - > CanInteractWithEnemies ( ) & & u2 - > IsFriendly ( ) ) | |
( ! u - > IsFriendly ( ) & & u - > CanInteractWithAllies ( ) & & ! u2 - > IsFriendly ( ) & & u - > AutoAcquiresFriendlyTargets ( ) ) ;
if ( canInteract ) {
geom2d : : line < float > unitLine ( u - > GetPos ( ) , u2 - > GetPos ( ) ) ;
if ( unitLine . length ( ) < closestDist ) {
closestUnit = u2 ;
closestDist = unitLine . length ( ) ;
}
}
}
void VirusAttack : : DrawMinimap ( ) {
DrawDecal ( GetScreenSize ( ) - IMAGES [ MINIMAP_HUD ] - > Sprite ( ) - > Size ( ) , IMAGES [ MINIMAP_HUD ] - > Decal ( ) , { 1 , 1 } ) ;
vf2d minimapTL = GetScreenSize ( ) - vf2d { 64 , 64 } ;
vi2d worldPixelSize = WORLD_SIZE * CONSTANT : : TILE_SIZE ;
vf2d viewingTilesPct = vf2d { float ( ScreenWidth ( ) ) , float ( ScreenHeight ( ) ) } / CONSTANT : : TILE_SIZE / WORLD_SIZE ;
SetDrawTarget ( IMAGES [ MINIMAP_OUTLINE ] - > Sprite ( ) ) ;
Clear ( BLANK ) ;
DrawRect ( ( gametv . GetWorldOffset ( ) / worldPixelSize * 64 ) , viewingTilesPct * 64 / gametv . GetWorldScale ( ) ) ;
for ( auto & cp : collectionPoints ) {
Pixel col ;
switch ( cp - > type ) {
case HEALTH : {
col = CONSTANT : : HEALTH_COLOR ;
} break ;
case ATKSPD : {
col = CONSTANT : : ATKSPD_COLOR ;
} break ;
case MOVESPD : {
col = CONSTANT : : MOVESPD_COLOR ;
} break ;
case RANGE : {
col = CONSTANT : : RANGE_COLOR ;
} break ;
case PROCEDURE : {
col = CONSTANT : : PROCEDURE_COLOR ;
} break ;
}
FillCircle ( cp - > pos / worldPixelSize * 64 - vf2d { 1 , 0 } , 1 , col ) ;
DrawCircle ( cp - > pos / worldPixelSize * 64 - vf2d { 1 , 0 } , 1 , BLACK ) ;
}
for ( auto & u : units ) {
vf2d squareSize = u - > GetUnitSize ( ) / vf2d ( WORLD_SIZE ) ;
squareSize . x = std : : round ( std : : max ( 1.f , squareSize . x ) ) ;
squareSize . y = std : : round ( std : : max ( 1.f , squareSize . y ) ) ;
float colorMult = 1 ;
if ( u - > IsAttached ( ) ) { colorMult = 0.5 ; }
FillRect ( u - > GetGhostPos ( ) / worldPixelSize * 64 - squareSize , squareSize * 2 , ( u - > IsFriendly ( ) ? GREEN : RED ) * colorMult ) ;
}
IMAGES [ MINIMAP_OUTLINE ] - > Decal ( ) - > Update ( ) ;
SetDrawTarget ( nullptr ) ;
DrawDecal ( minimapTL , IMAGES [ MINIMAP_OUTLINE ] - > Decal ( ) ) ;
}
void VirusAttack : : HandlePanAndZoom ( float fElapsedTime ) {
float speedScale = std : : min ( 1.f , gametv . GetWorldScale ( ) . x ) ;
bool canMouseScroll = ! memoryAllocatorBox . IsVisible ( ) & & ! unitCreationBox . IsVisible ( ) & &
( GetMouseY ( ) < = ScreenHeight ( ) - 64 | | GetMouseX ( ) < = ScreenWidth ( ) - 64
| | GetMouseScreenX ( ) > = GetWindowPos ( ) . x + GetWindowSize ( ) . x | | GetMouseScreenY ( ) > = GetWindowPos ( ) . y + GetWindowSize ( ) . y ) & & ! restartBox . IsVisible ( ) ;
if ( GetKey ( A ) . bHeld | | canMouseScroll & & GetMouseScreenX ( ) < = GetWindowPos ( ) . x + CONSTANT : : SCROLL_BOUNDARY ) {
vf2d amt = vf2d { - 300 * fElapsedTime , 0 } / speedScale ;
gametv . MoveWorldOffset ( amt ) ;
}
if ( GetKey ( W ) . bHeld | | canMouseScroll & & GetMouseScreenY ( ) < = GetWindowPos ( ) . y + CONSTANT : : SCROLL_BOUNDARY + 24 ) {
gametv . MoveWorldOffset ( vf2d { 0 , - 300 * fElapsedTime } / speedScale ) ;
}
if ( GetKey ( S ) . bHeld | | canMouseScroll & & GetMouseScreenY ( ) > = GetWindowPos ( ) . y + GetWindowSize ( ) . y - CONSTANT : : SCROLL_BOUNDARY ) {
gametv . MoveWorldOffset ( vf2d { 0 , 300 * fElapsedTime } / speedScale ) ;
}
if ( GetKey ( D ) . bHeld | | canMouseScroll & & GetMouseScreenX ( ) > = GetWindowPos ( ) . x + GetWindowSize ( ) . x - CONSTANT : : SCROLL_BOUNDARY ) {
vf2d amt = vf2d { 300 * fElapsedTime , 0 } / speedScale ;
gametv . MoveWorldOffset ( amt ) ;
}
if ( GetMouseWheel ( ) > 0 ) {
if ( gametv . GetWorldScale ( ) . x < 2 ) {
gametv . ZoomAtScreenPos ( 1.25 , GetMousePos ( ) ) ;
}
} else
if ( GetMouseWheel ( ) < 0 ) {
if ( gametv . GetWorldScale ( ) . x > 0.5 ) {
gametv . ZoomAtScreenPos ( 0.75 , GetMousePos ( ) ) ;
}
}
}
void VirusAttack : : HandleMinimapClick ( ) {
if ( startingDragPos = = CONSTANT : : UNSELECTED & & GetMouse ( 0 ) . bHeld & & GetMouseX ( ) > = ScreenWidth ( ) - 64 & & GetMouseY ( ) > = ScreenHeight ( ) - 64 ) {
vf2d minimapTL = GetScreenSize ( ) - vf2d { 64 , 64 } ;
gametv . SetWorldOffset ( vf2d ( GetMousePos ( ) - minimapTL ) / 64 * WORLD_SIZE * CONSTANT : : TILE_SIZE - vf2d ( GetScreenSize ( ) ) / gametv . GetWorldScale ( ) / 2.f ) ;
}
vf2d offset = gametv . GetWorldOffset ( ) ;
offset . x = std : : clamp ( float ( offset . x ) , - ScreenWidth ( ) / 2 / gametv . GetWorldScale ( ) . x , WORLD_SIZE . x * 24 - ( ScreenWidth ( ) / 2 / gametv . GetWorldScale ( ) . x ) ) ;
offset . y = std : : clamp ( float ( offset . y ) , - ScreenHeight ( ) / 2 / gametv . GetWorldScale ( ) . y , WORLD_SIZE . y * 24 - ( ScreenHeight ( ) / 2 / gametv . GetWorldScale ( ) . y ) ) ;
gametv . SetWorldOffset ( offset ) ;
}
void VirusAttack : : UpdateMatrixTexture ( float fElapsedTime ) {
if ( matrixTimer = = 0 ) {
activeLetters . emplace_back ( vf2d { float ( rand ( ) % 64 ) , float ( 64 ) } , util : : random ( - 40 ) - 20 , matrixLetters [ rand ( ) % matrixLetters . size ( ) ] ) ;
matrixTimer = util : : random ( 0.125 ) ;
}
if ( updatePixelsTimer = = 0 ) {
SetDrawTarget ( IMAGES [ MATRIX ] - > Sprite ( ) ) ;
Sprite * img = IMAGES [ MATRIX ] - > Sprite ( ) ;
for ( int y = 63 ; y > = 0 ; y - - ) {
for ( int x = 63 ; x > = 0 ; x - - ) {
Pixel col = img - > GetPixel ( x , y ) ;
if ( col . r > 0 ) {
if ( x > 0 ) {
Pixel leftCol = img - > GetPixel ( x - 1 , y ) ;
if ( leftCol . r < col . r ) {
leftCol = PixelLerp ( col , leftCol , 0.125 ) ;
}
Draw ( x - 1 , y , leftCol ) ;
}
if ( x < img - > width - 1 ) {
Pixel rightCol = img - > GetPixel ( x + 1 , y ) ;
if ( rightCol . r < col . r ) {
rightCol = PixelLerp ( col , rightCol , 0.125 ) ;
}
Draw ( x + 1 , y , rightCol ) ;
}
col / = 8 ;
Draw ( x , y , col ) ;
}
}
}
for ( int y = 0 ; y < 64 ; y + + ) {
Draw ( { 0 , y } , img - > GetPixel ( 1 , y ) ) ;
}
SetDrawTarget ( nullptr ) ;
updatePixelsTimer = 0.1 ;
}
if ( activeLetters . size ( ) > 0 ) {
SetDrawTarget ( IMAGES [ MATRIX ] - > Sprite ( ) ) ;
for ( Letter & letter : activeLetters ) {
letter . pos . y + = letter . spd * fElapsedTime ;
DrawString ( letter . pos , std : : string ( 1 , letter . c ) ) ;
}
SetDrawTarget ( nullptr ) ;
IMAGES [ MATRIX ] - > Decal ( ) - > Update ( ) ;
}
matrixTimer = std : : max ( 0.f , matrixTimer - fElapsedTime ) ;
updatePixelsTimer = std : : max ( 0.f , updatePixelsTimer - fElapsedTime ) ;
std : : erase_if ( activeLetters , [ ] ( Letter & letter ) { return letter . pos . y < - 32 ; } ) ;
}
void VirusAttack : : RenderCollectionPoints ( CollectionPoint * cp ) {
geom2d : : rect < float > cpRect = geom2d : : rect < float > ( { cp - > pos - cp - > img . Sprite ( ) - > Size ( ) / 2 , cp - > img . Sprite ( ) - > Size ( ) } ) ;
geom2d : : rect < float > viewRegion = geom2d : : rect < float > ( { gametv . GetWorldTL ( ) , gametv . GetWorldVisibleArea ( ) } ) ;
if ( geom2d : : overlaps ( cpRect , viewRegion ) ) {
Pixel col ;
switch ( cp - > type ) {
case HEALTH : {
col = CONSTANT : : HEALTH_COLOR ;
} break ;
case RANGE : {
col = CONSTANT : : RANGE_COLOR ;
} break ;
case ATKSPD : {
col = CONSTANT : : ATKSPD_COLOR ;
} break ;
case MOVESPD : {
col = CONSTANT : : MOVESPD_COLOR ;
} break ;
case PROCEDURE : {
col = CONSTANT : : PROCEDURE_COLOR ;
} break ;
}
gametv . DrawRotatedDecal ( cp - > pos , cp - > img . Decal ( ) , cp - > rot , cp - > img . Sprite ( ) - > Size ( ) / 2 , { 1 , 1 } , col ) ;
if ( geom2d : : overlaps ( cpRect , GetWorldMousePos ( ) ) ) {
gametv . DrawRotatedDecal ( cp - > pos , IMAGES [ MEMORY_COLLECTION_POINT_HIGHLIGHT ] - > Decal ( ) , cp - > rot , cp - > img . Sprite ( ) - > Size ( ) / 2 , { 1 , 1 } , col ) ;
}
}
}
bool VirusAttack : : OnUserUpdate ( float fElapsedTime ) {
UpdateMatrixTexture ( fElapsedTime ) ;
gameplayTime + = fElapsedTime ;
if ( state ! = GameState : : COMPLETED ) {
if ( gameplayTime > = 1 ) {
gameplayTime - - ;
gameSeconds + + ;
}
}
switch ( state ) {
# pragma region MAIN_MENU
case GameState : : MAIN_MENU : {
mainMenu . Update ( this ) ;
if ( campaignStartButton - > bPressed ) {
SOUNDS [ Sound : : BUTTONSELECT ] - > PlayCentered ( ) ;
state = GameState : : GAMEPLAY ;
RestartLevel ( ) ;
gameplayTime = 0 ;
gameSeconds = 0 ;
}
if ( audioToggleButton - > bPressed ) {
audioMode = ( audioMode + 1 ) % 3 ;
switch ( audioMode ) {
case 0 : {
AL . bMusicOn = AL . bSoundOn = true ;
bgm_handle = bgm - > PlayCentered ( ) ;
audioToggleButton - > sText = " Audio: On " ;
} break ;
case 1 : {
AL . bSoundOn = true ;
AL . bMusicOn = false ;
bgm - > Stop ( bgm_handle ) ;
audioToggleButton - > sText = " Audio: SE Only " ;
} break ;
case 2 : {
AL . bMusicOn = AL . bSoundOn = false ;
audioToggleButton - > sText = " Audio: Off " ;
} break ;
}
}
if ( difficultyToggleButton - > bPressed ) {
flags . difficulty = ( flags . difficulty + 1 ) % 3 ;
switch ( flags . difficulty ) {
case 0 : {
difficultyToggleButton - > sText = " Difficulty: Easy " ;
} break ;
case 1 : {
difficultyToggleButton - > sText = " Difficulty: Normal " ;
} break ;
case 2 : {
difficultyToggleButton - > sText = " Difficulty: Hard " ;
} break ;
}
}
if ( exitGameButton - > bPressed ) {
SOUNDS [ Sound : : BUTTONSELECT ] - > PlayCentered ( ) ;
return false ;
}
titleScreenY = std : : min ( 0.f , titleScreenY + fElapsedTime * 120 ) ;
nextColorChange = std : : max ( 0.f , nextColorChange - fElapsedTime ) ;
transition = std : : min ( 1.f , transition + fElapsedTime ) ;
if ( nextColorChange = = 0 ) {
currentBackCol = newCol ;
newCol = colorChangeOptions [ rand ( ) % colorChangeOptions . size ( ) ] ;
randomBackgroundOffset = { util : : random ( 128 ) , util : : random ( 128 ) } ;
nextColorChange = 10 ;
transition = 0 ;
}
if ( titleScreenY = = 0 ) {
textOrientationX = std : : max ( 0.f , textOrientationX - fElapsedTime * 50 ) ;
textOrientationY = std : : max ( 0.f , textOrientationY - fElapsedTime * 25 ) ;
}
DrawPartialDecal ( { 0 , 0 } , GetScreenSize ( ) , IMAGES [ MATRIX ] - > Decal ( ) , randomBackgroundOffset + gametv . GetWorldOffset ( ) * ( vf2d { 32 , 32 } / vf2d ( GetScreenSize ( ) ) ) * gametv . GetWorldScale ( ) , { 32 , 32 } , PixelLerp ( Pixel { currentBackCol . r , currentBackCol . g , currentBackCol . b , 255 } , Pixel { newCol . r , newCol . g , newCol . b , 255 } , transition ) ) ;
vf2d setPieceOffset = { 48 , titleScreenY } ;
{
vf2d offset = vf2d { 0 , 0 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ RAM_BANK ] - > Decal ( ) , { vf2d { 24 , 24 } + offset , vf2d { 24 , 104 } + offset , vf2d { 72 , 88 } + offset , vf2d { 72 , 40 } + offset } , Pixel { 192 , 192 , 255 } ) ;
}
{
vf2d offset = vf2d { 100 , - 52 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ MEMORY_GUARD ] - > Decal ( ) , { vf2d { 20 , 48 } + offset , vf2d { 20 , 108 } + offset , vf2d { 96 , 104 } + offset , vf2d { 96 , 52 } + offset } , Pixel { 192 , 192 , 255 } ) ;
}
{
vf2d offset = vf2d { 76 , - 20 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ BIT_RESTORER ] - > Decal ( ) , { vf2d { 12 , 52 } + offset , vf2d { 12 , 104 } + offset , vf2d { 64 , 92 } + offset , vf2d { 64 , 64 } + offset } , Pixel { 192 , 192 , 255 } ) ;
}
DrawCurvedTexture ( vf2d { 170 - 48 , 70 } + setPieceOffset , { - 30 , - 20 } , attackingLineModified . Decal ( ) , { arrowScroll / 2 , 0 } , CONSTANT : : HEALER_ATTACK_COL , 1.5 ) ;
{
vf2d offset = vf2d { 48 , 0 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ LEFT_SHIFTER ] - > Decal ( ) , { vf2d { 20 , 48 } + offset , vf2d { 20 , 108 } + offset , vf2d { 68 , 96 } + offset , vf2d { 68 , 60 } + offset } , Pixel { 192 , 192 , 255 } ) ;
}
if ( flickerAmt > 0.6 ) {
flickerAmt - = util : : random ( 0.4 ) ;
} else {
flickerAmt = 1 ;
}
DrawDecal ( vf2d { 12 , - 28 } + setPieceOffset , IMAGES [ SHIELD_BUBBLE ] - > Decal ( ) , { 2.4 , 2.8 } , { 255 , 255 , 255 , uint8_t ( flickerAmt * 255 ) } ) ;
{
vf2d offset = vf2d { 250 , - 18 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ RAM_BANK ] - > Decal ( ) , { vf2d { 8 , 38 } + offset , vf2d { 8 , 90 } + offset , vf2d { 68 , 102 } + offset , vf2d { 68 , 26 } + offset } , Pixel { 255 , 192 , 192 } ) ;
}
{
vf2d offset = vf2d { 220 , 0 } + setPieceOffset ;
DrawWarpedDecal ( IMAGES [ MEMORY_SWAPPER ] - > Decal ( ) , { vf2d { 20 , 60 } + offset , vf2d { 20 , 96 } + offset , vf2d { 68 , 108 } + offset , vf2d { 68 , 48 } + offset } , Pixel { 255 , 192 , 192 } ) ;
}
arrowScroll - = fElapsedTime * 2 ;
SetDrawTarget ( attackingLineModified . Sprite ( ) ) ;
Clear ( BLANK ) ;
for ( int y = 0 ; y < IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > height ; y + + ) {
for ( int x = 0 ; x < IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > width ; x + + ) {
Pixel col = IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > GetPixel ( x , y ) ;
if ( col . a > 0 ) {
if ( col = = WHITE ) {
Draw ( x , y , IMAGES [ MATRIX ] - > Sprite ( ) - > GetPixel ( x , y ) ) ;
} else {
Draw ( x , y , IMAGES [ ATTACKING_LINE ] - > Sprite ( ) - > GetPixel ( x , y ) ) ;
}
}
}
}
SetDrawTarget ( nullptr ) ;
attackingLineModified . Decal ( ) - > Update ( ) ;
//DrawPartialWarpedDecal()
DrawCurvedTexture ( vf2d { 150 - 48 , 80 } + setPieceOffset , { 160 , - 30 } , attackingLineModified . Decal ( ) , { arrowScroll , 0 } , CONSTANT : : ATTACKER_ATTACK_COL , 0.8 ) ;
{
vf2d offset = { 0 , 20 } ;
DrawWarpedDecal ( titleScreenText . Decal ( ) , { vf2d { float ( textOrientationX ) , float ( textOrientationY ) } + offset , vf2d { 0 , float ( titleScreenText . Sprite ( ) - > height ) } + offset , vf2d { float ( titleScreenText . Sprite ( ) - > width ) , float ( titleScreenText . Sprite ( ) - > height ) } + offset , vf2d { float ( titleScreenText . Sprite ( ) - > width - textOrientationX ) , float ( textOrientationY ) } + offset } ) ;
}
mainMenu . DrawDecal ( this ) ;
} break ;
# pragma endregion
# pragma region GAMEPLAY
case GameState : : GAMEPLAY : {
HandleGUIDisplay ( ) ;
if ( flags . playerInControl ) {
HandleDraggingSelection ( ) ;
HandleRightClickMove ( ) ;
HandlePanAndZoom ( fElapsedTime ) ;
HandleMinimapClick ( ) ;
}
flashTimer + = fElapsedTime * 2 ;
if ( flashTimer > 1 ) {
flashTimer - - ;
}
SCENARIOS [ currentScenario ] - > _Update ( enemy_resources , collectionPoints , currentLevel - > availableMemory - GetTotalUsedMemory ( ) , queuedUnits , SOUNDS ) ;
if ( SCENARIOS [ currentScenario ] - > transitionToNextLevel ) {
if ( SCENARIOS [ currentScenario ] - > nextLevel ! = FINISH ) {
levelToLoad = SCENARIOS [ currentScenario ] - > nextLevel ;
} else {
state = GameState : : COMPLETED ;
}
}
restartManager . Update ( this ) ;
HandleRestartButton ( fElapsedTime ) ;
PerformLevelTransition ( fElapsedTime ) ;
AL . vecPos = gametv . ScreenToWorld ( GetScreenSize ( ) / 2 ) ;
AL . fSoundFXVolume = std : : min ( 1.f , gametv . GetWorldScale ( ) . x ) ;
AL . OnUserUpdate ( fElapsedTime ) ;
for ( auto & tile : TileManager : : visibleTiles ) {
tile . second - = fElapsedTime ;
}
std : : erase_if ( TileManager : : visibleTiles , [ ] ( std : : pair < vf2d , float > key ) { return key . second < = 0 ; } ) ;
CalculateUsedMemory ( ) ;
for ( auto & u : units ) {
u - > SaveMemory ( ) ;
std : : weak_ptr < Unit > closestUnit ;
float closestDist = 999999 ;
for ( auto & u2 : units ) {
IdentifyClosestTarget ( closestUnit , closestDist , u , u2 ) ;
CollisionChecking ( u , u2 ) ;
}
if ( u - > IsFriendly ( ) ) {
for ( int y = - 2 ; y < 3 ; y + + ) {
for ( int x = - 2 ; x < 3 ; x + + ) {
if ( abs ( x ) + abs ( y ) < = 2 ) {
TileManager : : visibleTiles [ u - > GetPos ( ) / 24 / 4 + vi2d ( x , y ) ] = 5 ;
}
}
}
}
u - > AttemptAttack ( u , closestUnit , units , debuffIcons , IMAGES , SOUNDS ) ;
u - > _Update ( this , SOUNDS , player_resources , enemy_resources , queuedUnits , resourceGainTimer , resourceGainIcons , IMAGES , flags ) ;
}
std : : erase_if ( units , [ & ] ( std : : shared_ptr < Unit > u ) {
if ( u - > GetHealth ( ) = = 0 ) {
u - > _OnDeath ( SOUNDS ) ;
deathAnimations . emplace_back ( std : : make_unique < DeathAnimation > ( this , u - > GetPos ( ) , u - > GetImage ( ) , * IMAGES [ MATRIX ] , u - > IsFriendly ( ) ) ) ;
return true ;
} else {
return false ;
}
} ) ;
for ( auto & queuedUnit : queuedUnits ) {
units . push_back ( std : : move ( queuedUnit ) ) ;
}
queuedUnits . clear ( ) ;
DrawPartialDecal ( { 0 , 0 } , GetScreenSize ( ) , IMAGES [ MATRIX ] - > Decal ( ) , randomBackgroundOffset + gametv . GetWorldOffset ( ) * ( vf2d { 32 , 32 } / vf2d ( GetScreenSize ( ) ) ) * gametv . GetWorldScale ( ) , { 32 , 32 } , Pixel { currentLevel - > levelColor . r , currentLevel - > levelColor . g , currentLevel - > levelColor . b , 164 } / 2 ) ;
gametv . DrawPartialDecal ( { 0 , 0 } , WORLD_SIZE * CONSTANT : : TILE_SIZE , IMAGES [ TILE ] - > Decal ( ) , { 0 , 0 } , WORLD_SIZE * CONSTANT : : TILE_SIZE , currentLevel - > levelColor ) ;
for ( auto & u : units ) {
u - > DrawRangeIndicator ( this , gametv , IMAGES ) ;
}
for ( auto & u : units ) {
u - > Draw ( gametv , IMAGES ) ;
if ( u - > IsGuarded ( ) & & ! u - > InFogOfWar ( ) ) {
gametv . DrawDecal ( u - > GetPos ( ) + vf2d { float ( u - > GetUnitSize ( ) . x / 2 ) , - float ( u - > GetUnitSize ( ) . y / 2 ) } - vf2d { float ( IMAGES [ GUARD_ICON ] - > Sprite ( ) - > width ) , 0.f } * 0.375 , IMAGES [ GUARD_ICON ] - > Decal ( ) , { 0.375 , 0.375 } ) ;
}
}
for ( auto & deadUnit : deathAnimations ) {
deadUnit - > Update ( fElapsedTime ) ;
deadUnit - > Draw ( gametv , this ) ;
}
std : : erase_if ( deathAnimations , [ ] ( auto & u ) { return u - > IsDone ( ) ; } ) ;
for ( auto & collectionPoint : collectionPoints ) {
collectionPoint - > Update ( this , * IMAGES [ MATRIX ] ) ;
RenderCollectionPoints ( collectionPoint . get ( ) ) ;
}
for ( auto & u : units ) {
u - > DrawUnitDamageStats ( this , gametv , IMAGES ) ;
}
for ( DebuffIcon & icon : debuffIcons ) {
icon . Update ( fElapsedTime ) ;
icon . Draw ( gametv ) ;
}
for ( ResourceGainIcon & icon : resourceGainIcons ) {
icon . Update ( fElapsedTime ) ;
icon . Draw ( gametv ) ;
}
std : : erase_if ( debuffIcons , [ ] ( DebuffIcon & icon ) { return icon . lifetime < = 0 ; } ) ;
std : : erase_if ( resourceGainIcons , [ ] ( ResourceGainIcon & icon ) { return icon . lifetime < = 0 ; } ) ;
for ( auto & u : units ) {
u - > _DrawHud ( gametv , IMAGES , flags . unitMetersGreyedOut ) ;
}
DrawSelectionRectangle ( ) ;
RenderFogOfWar ( ) ;
unitCreationList . DrawDecal ( this ) ;
platformCreationList . DrawDecal ( this ) ;
restartManager . DrawDecal ( this ) ;
DrawSystemMemoryBar ( fElapsedTime ) ;
DrawResourceBar ( fElapsedTime ) ;
if ( flags . guideEnabled ) {
DrawDecal ( { float ( ScreenWidth ( ) - 74 - IMAGES [ GUIDE ] - > Sprite ( ) - > width * 0.75 ) , float ( ScreenHeight ( ) + 6 - IMAGES [ GUIDE ] - > Sprite ( ) - > height * 0.75 ) } , IMAGES [ GUIDE ] - > Decal ( ) , { 0.75 , 0.75 } ) ;
}
DrawMinimap ( ) ;
unitCreationBox . UpdateAndDraw ( GetMousePos ( ) + vi2d { 8 , - 28 } , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
testBox . UpdateAndDraw ( GetMousePos ( ) - testBox . GetSize ( ) / 2 , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
memoryAllocatorBox . UpdateAndDraw ( GetMousePos ( ) + vi2d { 8 , - 28 } , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
platformCreationBox . UpdateAndDraw ( GetMousePos ( ) + vi2d { 8 , - 28 } , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
restartBox . UpdateAndDraw ( GetMousePos ( ) + vf2d { 0 , 10 } , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
if ( restartButtonHoldTime > 0 ) {
FillRectDecal ( restartButton - > vPos + vf2d { 3 , ( 1 - ( restartButtonHoldTime / 2.5f ) ) * restartButton - > vSize . y } , { restartButton - > vSize . x , ( ( restartButtonHoldTime / 2.5f ) ) * restartButton - > vSize . y } , { 255 , 255 , 255 , 128 } ) ;
}
std : : sort ( units . begin ( ) , units . end ( ) , [ & ] ( auto & u1 , auto & u2 ) {
float dist1 = geom2d : : line < float > ( u1 - > GetGhostPos ( ) , GetWorldMousePos ( ) ) . length ( ) ;
float dist2 = geom2d : : line < float > ( u2 - > GetGhostPos ( ) , GetWorldMousePos ( ) ) . length ( ) ;
return dist1 > dist2 ; } ) ;
SCENARIOS [ currentScenario ] - > Draw ( ) ;
for ( auto & u : units ) {
if ( u - > IsGuarded ( ) ) {
bool changeOccured = false ;
int changedBit = - 1 ;
for ( int i = 0 ; i < u - > memory . size ( ) ; i + + ) {
if ( u - > memory [ i ] ! = u - > savedMemory [ i ] ) {
changeOccured = true ;
changedBit = i ;
break ;
}
}
if ( changeOccured & & util : : random ( 1 ) < = 0.3 ) {
u - > memory [ changedBit ] = u - > savedMemory [ changedBit ] ;
}
}
}
DrawPartialDecal ( { 0 , 0 } , GetScreenSize ( ) , IMAGES [ MATRIX ] - > Decal ( ) , randomBackgroundOffset + gametv . GetWorldOffset ( ) * ( vf2d { 32 , 32 } / vf2d ( GetScreenSize ( ) ) ) * gametv . GetWorldScale ( ) , { 32 , 32 } , Pixel { currentLevel - > levelColor . r , currentLevel - > levelColor . g , currentLevel - > levelColor . b , uint8_t ( levelForegroundFade * 255 ) } / 2 ) ;
} break ;
# pragma endregion
# pragma region COMPLETED
case GameState : : COMPLETED : {
DrawPartialDecal ( { 0 , 0 } , GetScreenSize ( ) , IMAGES [ MATRIX ] - > Decal ( ) , randomBackgroundOffset + gametv . GetWorldOffset ( ) * ( vf2d { 32 , 32 } / vf2d ( GetScreenSize ( ) ) ) * gametv . GetWorldScale ( ) , { 32 , 32 } , Pixel { currentLevel - > levelColor . r , currentLevel - > levelColor . g , currentLevel - > levelColor . b , 164 } / 2 ) ;
completedBox . Initialize ( " Thank you for playing Virus Attack! \n \n Completion Time: " + DisplayTime ( gameSeconds ) + " seconds \n Difficulty Completed: \n + " + ( flags . difficulty = = 0 ? " Easy " : flags . difficulty = = 1 ? " Normal " : " Hard " ) + " + \n \n Huge shoutout to the OLC community, javidx9 for the PGE existing, and all supporters! \n \n \n Press [Escape] to return to the main menu. " , { 0 , 0 } , " Congratulations! " , nullptr , { float ( ScreenWidth ( ) - 2 ) , 1.f } ) ;
completedBox . UpdateAndDraw ( { 0 , 0 } , this , player_resources , IMAGES , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
if ( GetKey ( ESCAPE ) . bPressed ) {
state = GameState : : MAIN_MENU ;
float titleScreenY = - 200 ;
float textOrientationY = 0 ;
float textOrientationX = 0 ;
levelToLoad = LevelName : : STAGE1 ;
}
} break ;
# pragma endregion
}
return true ;
}
std : : string VirusAttack : : DisplayTime ( int gameSeconds ) {
int totalMinutes = gameSeconds / 60 ;
int totalHours = totalMinutes / 60 ;
std : : string secondsDisplay = std : : to_string ( gameSeconds % 60 ) ;
std : : string minutesDisplay = std : : to_string ( totalMinutes % 60 ) ;
std : : string hoursDisplay = std : : to_string ( totalHours ) ;
return hoursDisplay + " : " + ( ( minutesDisplay . length ( ) = = 1 ) ? " 0 " : " " ) + minutesDisplay + " : " + ( ( secondsDisplay . length ( ) = = 1 ) ? " 0 " : " " ) + secondsDisplay ;
}
void VirusAttack : : DrawSystemMemoryBar ( float fElapsedTime ) {
memoryChangeTimer = std : : max ( 0.f , memoryChangeTimer - fElapsedTime ) ;
memoryDisplayDelay - = fElapsedTime ;
if ( memoryDisplayDelay < = 0 ) {
if ( memoryDisplayAmt > lastTotalMemory ) {
memoryDisplayAmt - = 1 ;
} else
if ( memoryDisplayAmt < lastTotalMemory ) {
memoryDisplayAmt + = 1 ;
}
memoryDisplayDelay = 0.01 ;
}
lastDisplayMemoryUpdateTimer - = fElapsedTime ;
if ( lastDisplayMemoryUpdateTimer < = 0 ) {
for ( int i = 0 ; i < playerUsedMemory . size ( ) ; i + + ) {
if ( playerUsedMemory [ i ] < playerUsedDisplayMemory [ i ] ) {
playerUsedDisplayMemory [ i ] - - ;
} else
if ( playerUsedMemory [ i ] > playerUsedDisplayMemory [ i ] ) {
playerUsedDisplayMemory [ i ] + + ;
}
}
for ( int i = 0 ; i < enemyUsedMemory . size ( ) ; i + + ) {
if ( enemyUsedMemory [ i ] < enemyUsedDisplayMemory [ i ] ) {
enemyUsedDisplayMemory [ i ] - - ;
} else
if ( enemyUsedMemory [ i ] > enemyUsedDisplayMemory [ i ] ) {
enemyUsedDisplayMemory [ i ] + + ;
}
}
lastDisplayMemoryUpdateTimer = 0.01 ;
}
vf2d barPos = { 2 , float ( ScreenHeight ( ) - 7 ) } ;
float barOffset = 0 ;
float barWidth = 240 ;
float actualBarWidth = barWidth + 2 ;
for ( int i = 0 ; i < playerUsedDisplayMemory . size ( ) ; i + + ) {
float barSegmentWidth = ( float ( playerUsedDisplayMemory [ i ] ) / currentLevel - > availableMemory ) * actualBarWidth ;
Pixel col ;
switch ( i ) {
case 0 : {
col = CONSTANT : : HEALTH_COLOR ;
} break ;
case 1 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : RANGE_COLOR ;
} break ;
case 2 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : ATKSPD_COLOR ;
} break ;
case 3 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : MOVESPD_COLOR ;
} break ;
case 4 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : PROCEDURE_COLOR ;
} break ;
}
DrawPartialDecal ( barPos + vf2d { barOffset + 1 , 1.f } , { barSegmentWidth , 3 } , IMAGES [ SEGMENT_BAR ] - > Decal ( ) , { 0 , 0 } , { float ( playerUsedDisplayMemory [ i ] ) , 3.f } , col ) ;
barOffset + = barSegmentWidth ;
}
FillRectDecal ( barPos + vf2d { barOffset + 1 , 1.f } , { 2 , 3 } , GREEN ) ;
barOffset = 0 ;
for ( int i = 0 ; i < enemyUsedDisplayMemory . size ( ) ; i + + ) {
float barSegmentWidth = ( float ( enemyUsedDisplayMemory [ i ] ) / currentLevel - > availableMemory ) * actualBarWidth ;
Pixel col ;
switch ( i ) {
case 0 : {
col = CONSTANT : : HEALTH_COLOR ;
} break ;
case 1 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : RANGE_COLOR ;
} break ;
case 2 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : ATKSPD_COLOR ;
} break ;
case 3 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : MOVESPD_COLOR ;
} break ;
case 4 : {
col = flags . unitMetersGreyedOut ? DARK_GREY : CONSTANT : : PROCEDURE_COLOR ;
} break ;
}
DrawPartialDecal ( barPos + vf2d { barOffset + actualBarWidth + 3 - barSegmentWidth , 1.f } , { barSegmentWidth , 3 } , IMAGES [ SEGMENT_BAR ] - > Decal ( ) , { 0 , 0 } , { float ( enemyUsedDisplayMemory [ i ] ) , 3.f } , col ) ;
barOffset - = barSegmentWidth ;
}
FillRectDecal ( barPos + vf2d { barOffset + actualBarWidth + 3 - 2 , 1.f } , { 2 , 3 } , RED ) ;
DrawPartialDecal ( barPos , { 3 , 5 } , IMAGES [ ROUND_BAR ] - > Decal ( ) , { 0 , 0 } , { 3 , 5 } , flags . flashMemoryBar ? PixelLerp ( BLACK , CONSTANT : : INCREASE_VALUE_COLOR , flashTimer ) : BLACK ) ;
for ( int i = barPos . x + 3 ; i < barWidth ; i + + ) {
DrawPartialDecal ( barPos + vf2d { 3 , 0 } , { barWidth , 5 } , IMAGES [ ROUND_BAR ] - > Decal ( ) , { 2 , 0 } , { 1 , 5 } , flags . flashMemoryBar ? PixelLerp ( BLACK , CONSTANT : : INCREASE_VALUE_COLOR , flashTimer ) : BLACK ) ;
}
DrawPartialDecal ( barPos + vf2d { 3 + barWidth , 0 } , { 3 , 5 } , IMAGES [ ROUND_BAR ] - > Decal ( ) , { 2 , 0 } , { 3 , 5 } , flags . flashMemoryBar ? PixelLerp ( BLACK , CONSTANT : : INCREASE_VALUE_COLOR , flashTimer ) : BLACK ) ;
vf2d textPos = barPos + vf2d { barWidth + 6 + 4 , 0 } ;
if ( GetTotalUsedMemory ( ) > lastTotalMemory ) {
memoryIncreased = true ;
memoryChangeTimer = 2 ;
} else
if ( GetTotalUsedMemory ( ) < lastTotalMemory ) {
memoryIncreased = false ;
memoryChangeTimer = 2 ;
}
lastTotalMemory = GetTotalUsedMemory ( ) ;
DrawShadowStringPropDecal ( textPos , std : : to_string ( memoryDisplayAmt ) + " / " + std : : to_string ( currentLevel - > availableMemory ) + " b " , WHITE , PixelLerp ( BLACK , memoryIncreased ? CONSTANT : : INCREASE_VALUE_COLOR : CONSTANT : : DECREASE_VALUE_COLOR , memoryChangeTimer / 2.0f ) , { 0.6 , 0.6 } , 0.6 ) ;
}
void VirusAttack : : DrawResourceBar ( float fElapsedTime ) {
for ( int i = 0 ; i < resourceGainTimer . size ( ) ; i + + ) {
resourceGainTimer [ i ] = std : : max ( 0.f , resourceGainTimer [ i ] - fElapsedTime ) ;
}
GradientFillRectDecal ( { 0 , 0 } , { float ( ScreenWidth ( ) ) , 12.f } , BLACK , { VERY_DARK_BLUE . r , VERY_DARK_BLUE . g , VERY_DARK_BLUE . b , 128 } , { VERY_DARK_BLUE . r , VERY_DARK_BLUE . g , VERY_DARK_BLUE . b , 128 } , BLACK ) ;
DrawRectDecal ( { 0 , 0 } , { float ( ScreenWidth ( ) ) , 12.f } , { 3 , 194 , 252 } ) ;
auto DrawResourceDisplay = [ & ] ( int index , int resourceValue , int & previousResourceValue , int & displayResourceValue , Pixel col ) {
resourceDisplayValueUpdateTimer [ index ] - = fElapsedTime ;
if ( previousResourceValue < resourceValue ) {
resourceIncreased [ index ] = true ;
resourceGainTimer [ index ] = 2 ;
previousResourceValue = resourceValue ;
} else
if ( previousResourceValue > resourceValue ) {
resourceIncreased [ index ] = false ;
resourceGainTimer [ index ] = 2 ;
previousResourceValue = resourceValue ;
}
if ( resourceDisplayValueUpdateTimer [ index ] < = 0 ) {
if ( displayResourceValue < resourceValue ) {
displayResourceValue + + ;
} else
if ( displayResourceValue > resourceValue ) {
displayResourceValue - - ;
}
resourceDisplayValueUpdateTimer [ index ] = 0.01 ;
}
DrawDecal ( { 6.f + index * 42 , 1.f } , IMAGES [ RESOURCE ] - > Decal ( ) , { 1 , 1 } , col ) ;
DrawShadowStringDecal ( { 6.f + index * 42 + 20 , 2.f } , std : : to_string ( displayResourceValue ) , col , PixelLerp ( BLACK , resourceIncreased [ index ] ? CONSTANT : : INCREASE_VALUE_COLOR : CONSTANT : : DECREASE_VALUE_COLOR , resourceGainTimer [ index ] / 2.0f ) ) ;
} ;
DrawResourceDisplay ( 0 , player_resources . health , player_prev_resources . health , player_display_resources . health , CONSTANT : : HEALTH_COLOR ) ;
DrawResourceDisplay ( 1 , player_resources . atkSpd , player_prev_resources . atkSpd , player_display_resources . atkSpd , CONSTANT : : ATKSPD_COLOR ) ;
DrawResourceDisplay ( 2 , player_resources . moveSpd , player_prev_resources . moveSpd , player_display_resources . moveSpd , CONSTANT : : MOVESPD_COLOR ) ;
DrawResourceDisplay ( 3 , player_resources . range , player_prev_resources . range , player_display_resources . range , CONSTANT : : RANGE_COLOR ) ;
DrawResourceDisplay ( 4 , player_resources . procedure , player_prev_resources . procedure , player_display_resources . procedure , CONSTANT : : PROCEDURE_COLOR ) ;
}
void VirusAttack : : RenderFogOfWar ( ) {
for ( int y = gametv . GetTopLeftTile ( ) . y / 96 - 1 ; y < = gametv . GetBottomRightTile ( ) . y / 96 + 1 ; y + + ) {
for ( int x = gametv . GetTopLeftTile ( ) . x / 96 - 1 ; x < = gametv . GetBottomRightTile ( ) . x / 96 + 1 ; x + + ) {
if ( TileManager : : visibleTiles . count ( vi2d { x , y } ) = = 0 ) {
if ( x > = 0 & & y > = 0 & & x < WORLD_SIZE . x / 4 & & y < WORLD_SIZE . y / 4 ) {
gametv . FillRectDecal ( vf2d { float ( x ) , float ( y ) } * 96 , { 96 , 96 } , { 0 , 0 , 0 , 128 } ) ;
}
}
}
}
}
bool VirusAttack : : CanAfford ( Resources & resources , std : : vector < Memory > & unitCosts ) {
int totalMemoryCost = 0 ;
for ( Memory & mem : unitCosts ) {
switch ( mem . type ) {
case HEALTH : {
if ( resources . health < mem . size ) return false ;
} break ;
case ATKSPD : {
if ( resources . atkSpd < mem . size ) return false ;
} break ;
case MOVESPD : {
if ( resources . moveSpd < mem . size ) return false ;
} break ;
case RANGE : {
if ( resources . range < mem . size ) return false ;
} break ;
case PROCEDURE : {
if ( resources . procedure < mem . size ) return false ;
} break ;
}
totalMemoryCost + = mem . size ;
}
return totalMemoryCost + GetTotalUsedMemory ( ) < = currentLevel - > availableMemory ;
}
void VirusAttack : : ExpendResources ( Resources & resources , std : : vector < Memory > & unitCosts ) {
for ( Memory & mem : unitCosts ) {
switch ( mem . type ) {
case HEALTH : {
resources . health - = mem . size ;
} break ;
case ATKSPD : {
resources . atkSpd - = mem . size ;
} break ;
case MOVESPD : {
resources . moveSpd - = mem . size ;
} break ;
case RANGE : {
resources . range - = mem . size ;
} break ;
case PROCEDURE : {
resources . procedure - = mem . size ;
} break ;
}
}
}
int VirusAttack : : GetTotalUsedMemory ( ) {
return GetPlayerUsedMemory ( ) + GetEnemyUsedMemory ( ) ;
}
int VirusAttack : : GetPlayerUsedMemory ( ) {
int sum = 0 ;
for ( int i = 0 ; i < 5 ; i + + ) {
sum + = playerUsedMemory [ i ] ;
}
return sum ;
}
int VirusAttack : : GetEnemyUsedMemory ( ) {
int sum = 0 ;
for ( int i = 0 ; i < 5 ; i + + ) {
sum + = enemyUsedMemory [ i ] ;
}
return sum ;
}
void VirusAttack : : CalculateUsedMemory ( ) {
playerUsedMemory = enemyUsedMemory = { 0 } ;
for ( auto & u : units ) {
std : : array < size_t , 5 > costs = { u - > health . size , u - > range . size , u - > atkSpd . size , u - > moveSpd . size , u - > procedure . size } ;
if ( u - > IsBuilding ( ) ) {
costs = { u - > GetBuildUnit ( ) - > health . size , u - > GetBuildUnit ( ) - > range . size , u - > GetBuildUnit ( ) - > atkSpd . size , u - > GetBuildUnit ( ) - > moveSpd . size , u - > GetBuildUnit ( ) - > procedure . size } ;
}
std : : array < int , 5 > & targetArr = u - > IsFriendly ( ) ? playerUsedMemory : enemyUsedMemory ;
for ( int i = 0 ; i < targetArr . size ( ) ; i + + ) {
targetArr [ i ] + = costs [ i ] ;
}
}
}
bool VirusAttack : : OnUserDestroy ( ) {
return true ;
}
void VirusAttack : : PerformLevelTransition ( float fElapsedTime ) {
if ( levelToLoad ! = currentLevel - > name | | reloadLevel ) {
levelForegroundFade = std : : min ( 1.f , levelForegroundFade + fElapsedTime ) ;
if ( levelForegroundFade > = 1 ) {
LoadLevel ( levelToLoad ) ;
reloadLevel = false ;
}
} else
if ( levelForegroundFade > 0 ) {
levelForegroundFade = std : : max ( 0.f , levelForegroundFade - fElapsedTime ) ;
}
}
void VirusAttack : : RestartLevel ( ) {
reloadLevel = true ;
}
void VirusAttack : : HandleRestartButton ( float fElapsedTime ) {
if ( restartButton - > bHover ) {
restartBox . Initialize ( " Click and hold to restart the level. " , GetMousePos ( ) + vf2d { 0 , 10 } , " Restart Level " , nullptr , { 72 , 1 } ) ;
restartBox . SetVisible ( true ) ;
if ( restartButton - > bPressed ) {
restartButtonHeldDown = true ;
}
if ( restartButton - > bReleased ) {
restartBox . SetVisible ( false ) ;
restartButtonHeldDown = false ;
restartButtonHoldTime = 0 ;
}
if ( restartButtonHeldDown ) {
restartButtonHoldTime + = fElapsedTime ;
if ( restartButtonHoldTime > = CONSTANT : : RESTART_BUTTON_HOLD_TIME ) {
RestartLevel ( ) ;
restartButtonHeldDown = false ;
restartButtonHoldTime = 0 ;
}
}
} else {
restartBox . SetVisible ( false ) ;
restartButtonHeldDown = false ;
restartButtonHoldTime = 0 ;
}
}
void VirusAttack : : DrawCurvedTexture ( vf2d offset , vf2d size , Decal * decal , vf2d texOffset , Pixel col , float curveThickness ) {
vf2d curveMultiplier = size ;
vf2d curveDisplacement = offset ;
std : : vector < vf2d > curvePoints = { { 0.f , abs ( sin ( ( 0 ) * float ( PI ) ) ) } , { 0.1 , abs ( sin ( ( 0.1f ) * float ( PI ) ) ) } , { 0.2 , abs ( sin ( ( 0.2f ) * float ( PI ) ) ) } , { 0.3 , abs ( sin ( ( 0.3f ) * float ( PI ) ) ) } , { 0.4 , abs ( sin ( ( 0.4f ) * float ( PI ) ) ) } , { 0.5 , abs ( sin ( ( 0.5f ) * float ( PI ) ) ) } , { 0.6 , abs ( sin ( ( 0.6f ) * float ( PI ) ) ) } , { 0.7 , abs ( sin ( ( 0.7f ) * float ( PI ) ) ) } , { 0.8 , abs ( sin ( ( 0.8f ) * float ( PI ) ) ) } , { 0.9 , abs ( sin ( ( 0.9f ) * float ( PI ) ) ) } , { 1.f , abs ( sin ( ( 1.f ) * float ( PI ) ) ) } } ;
vf2d curve2offset = { 0.f , curveThickness } ;
std : : vector < vf2d > curvePoints2 = { vf2d { 0.f , abs ( sin ( ( 0 ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.1 , abs ( sin ( ( 0.1f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.2 , abs ( sin ( ( 0.2f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.3 , abs ( sin ( ( 0.3f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.4 , abs ( sin ( ( 0.4f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.5 , abs ( sin ( ( 0.5f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.6f , abs ( sin ( ( 0.6f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.7 , abs ( sin ( ( 0.7f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.8 , abs ( sin ( ( 0.8f ) * float ( PI ) ) ) } + curve2offset , vf2d { 0.9 , abs ( sin ( ( 0.9f ) * float ( PI ) ) ) } + curve2offset , vf2d { 1.f , abs ( sin ( ( 1.f ) * float ( PI ) ) ) } + curve2offset } ;
std : : vector < vf2d > combinedCurvePoints = {
curvePoints2 [ 0 ] * curveMultiplier + curveDisplacement , curvePoints [ 0 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 1 ] * curveMultiplier + curveDisplacement , curvePoints [ 1 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 2 ] * curveMultiplier + curveDisplacement , curvePoints [ 2 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 3 ] * curveMultiplier + curveDisplacement , curvePoints [ 3 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 4 ] * curveMultiplier + curveDisplacement , curvePoints [ 4 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 5 ] * curveMultiplier + curveDisplacement , curvePoints [ 5 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 6 ] * curveMultiplier + curveDisplacement , curvePoints [ 6 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 7 ] * curveMultiplier + curveDisplacement , curvePoints [ 7 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 8 ] * curveMultiplier + curveDisplacement , curvePoints [ 8 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 9 ] * curveMultiplier + curveDisplacement , curvePoints [ 9 ] * curveMultiplier + curveDisplacement ,
curvePoints2 [ 10 ] * curveMultiplier + curveDisplacement , curvePoints [ 10 ] * curveMultiplier + curveDisplacement ,
} ;
std : : vector < vf2d > combinedUVPoints = {
{ curvePoints [ 0 ] . y + texOffset . x , 1 } , { curvePoints [ 0 ] . y + texOffset . x , 0 } ,
{ curvePoints [ 1 ] . y + texOffset . x , 1 } , { curvePoints [ 1 ] . y + texOffset . x , 0 } ,
{ curvePoints [ 2 ] . y + texOffset . x , 1 } , { curvePoints [ 2 ] . y + texOffset . x , 0 } ,
{ curvePoints [ 3 ] . y + texOffset . x , 1 } , { curvePoints [ 3 ] . y + texOffset . x , 0 } ,
{ curvePoints [ 4 ] . y + texOffset . x , 1 } , { curvePoints [ 4 ] . y + texOffset . x , 0 } ,
{ 1 - curvePoints [ 5 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 5 ] . y + texOffset . x + 1 , 0 } ,
{ 1 - curvePoints [ 6 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 6 ] . y + texOffset . x + 1 , 0 } ,
{ 1 - curvePoints [ 7 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 7 ] . y + texOffset . x + 1 , 0 } ,
{ 1 - curvePoints [ 8 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 8 ] . y + texOffset . x + 1 , 0 } ,
{ 1 - curvePoints [ 9 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 9 ] . y + texOffset . x + 1 , 0 } ,
{ 1 - curvePoints [ 10 ] . y + texOffset . x + 1 , 1 } , { 1 - curvePoints [ 10 ] . y + texOffset . x + 1 , 0 } ,
} ;
SetDecalStructure ( DecalStructure : : STRIP ) ;
DrawPolygonDecal ( decal , combinedCurvePoints , combinedUVPoints , col ) ;
SetDecalStructure ( DecalStructure : : FAN ) ;
}
void VirusAttack : : HandleGUIDisplay ( ) {
bool allocatorSelected = false ;
bool platformSelected = false ;
bool memoryAllocatorBoxHovered = false ;
for ( auto & u : units ) {
u - > UpdateGUIState ( gametv , player_resources , memoryAllocatorBox , memoryAllocatorBoxHovered , GetTotalUsedMemory ( ) , currentLevel - > availableMemory ) ;
if ( u - > IsSelected ( ) ) {
if ( u - > IsAllocator ( ) ) {
allocatorSelected = true ;
} else
if ( u - > IsPlatform ( ) ) {
platformSelected = true ;
}
}
}
if ( ! memoryAllocatorBoxHovered ) memoryAllocatorBox . SetVisible ( false ) ;
UpdateUnitCreationListGUI ( allocatorSelected ) ;
UpdatePlatformCreationListGUI ( platformSelected ) ;
}
int main ( )
{
VirusAttack app ;
if ( app . Construct ( 426 , 320 , 4 , 4 ) )
app . Start ( ) ;
return 0 ;
}