Add in resource gain overhead indicators.

CorrectiveAction
sigonasr2 1 year ago
parent ca39790119
commit 4b1cc3043a
  1. 28
      olcCodeJam2023Entry/DebuffIcon.cpp
  2. 10
      olcCodeJam2023Entry/DebuffIcon.h
  3. 39
      olcCodeJam2023Entry/Info.txt
  4. 5
      olcCodeJam2023Entry/Level.h
  5. 13
      olcCodeJam2023Entry/Unit.cpp
  6. 3
      olcCodeJam2023Entry/Unit.h
  7. 131
      olcCodeJam2023Entry/VirusAttack.cpp
  8. 3
      olcCodeJam2023Entry/VirusAttack.h
  9. 6
      olcCodeJam2023Entry/olcPGEX_TransformedView.h

@ -8,4 +8,32 @@ void DebuffIcon::Update(float fElapsedTime){
void DebuffIcon::Draw(TileTransformedView&game){
game.DrawRotatedDecal(pos,icon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{255,255,255,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)});
game.DrawRotatedDecal(pos+vf2d{4,-4},redXIcon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{255,255,255,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)});
}
void ResourceGainIcon::Update(float fElapsedTime){
pos.y-=6*fElapsedTime;
lifetime-=fElapsedTime;
}
void ResourceGainIcon::Draw(TileTransformedView&game){
Pixel col;
switch(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;
}
game.DrawRotatedDecal(pos,icon->Decal(),0,icon->Sprite()->Size()/2,{1,1},{col.r,col.g,col.b,uint8_t((lifetime/CONSTANT::DEBUFFICON_LIFETIME)*255)});
game.DrawShadowStringDecal(pos-vf2d{-2,-2},"+1",col);
}

@ -2,6 +2,7 @@
#include "olcPixelGameEngine.h"
#include "olcPGEX_TransformedView.h"
#include "Constant.h"
#include "MemoryType.h"
struct DebuffIcon{
Renderable*icon;
@ -10,4 +11,13 @@ struct DebuffIcon{
float lifetime=CONSTANT::DEBUFFICON_LIFETIME;
void Update(float fElapsedTime);
void Draw(TileTransformedView&game);
};
struct ResourceGainIcon{
Renderable*icon;
MemoryType type;
vf2d pos;
float lifetime=CONSTANT::DEBUFFICON_LIFETIME;
void Update(float fElapsedTime);
void Draw(TileTransformedView&game);
};

@ -91,7 +91,9 @@ Stage 3:
I'll leave a guide by the map in case your memory betrays you.
(Guide Enabled)
(New Scenario Objective:
-Defeat all enemy units)
-Defeat all units)
(Upon uncovering units and going near them)
Oh oops, I guess there were no viruses in this sector. Let's move on then.
Stage 4:
(Start with 3 of the yellow resource)
@ -110,31 +112,22 @@ Stage 5:
(New Scenario Objective:
-Defeat all enemy units)
Stage 6:
(New Scenario Objective:
-Defeat all enemy units)
...
Stage 7:
I see you have a few new tricks up your sleeve hacker.
Don't think it'll be that easy to get through this one...
(New Scenario Objective:
-Defeat all enemy units)
Stage 8:
You need to cease all operations, you are causing more harm than good.
(New Scenario Objective:
-Defeat all enemy units)
Tutorial
(Grey out non-important bars)
Level 1: Basic Unit and Controls, move units towards enemy unit
Level 2: Introduce another Unit
Level 3:
Level 4:
Level 5:
Level 6:
(Introduce one unit at a time)
Memory Limits
Minimap
Pause / Slow down time (Hotkeys to speed up/slow down time)
Stage 1
Stage 2
Stage 3
Stage 4
Stage 5 - Hacking a Network
Potential Songs:

@ -8,6 +8,10 @@ enum LevelName{
STAGE2,
STAGE3,
STAGE4,
STAGE5,
STAGE6,
STAGE7,
STAGE8,
};
struct UnitData{
@ -31,4 +35,5 @@ struct Level{
Sound bgm=Sound::COSMOS;
vf2d cameraStart={96,96};
vf2d worldZoom={1,1};
Pixel levelColor=DARK_GREEN;
};

@ -91,8 +91,10 @@ void MemorySwapper::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherU
if(victim.moveSpd.index<lowestInd){lowest=&victim.moveSpd;lowestInd=lowest->index;}
if(victim.procedure.index<lowestInd){lowest=&victim.procedure;lowestInd=lowest->index;}
order.push_back(lowest);
lowest->index=9999999;
if(lowest!=nullptr){
order.push_back(lowest);
lowest->index=9999999;
}
}
std::reverse(order.begin(),order.end());
int i=0;
@ -637,7 +639,7 @@ void Unit::_RunAI(PixelGameEngine*pge){
RunAI(pge);
}
void Unit::_Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::unique_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer){
void Unit::_Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::unique_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer,std::vector<ResourceGainIcon>&resourceGainIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
if(!target.expired()){
auto ptrTarget=target.lock();
if(!InRange(ptrTarget)&&CanMove()){
@ -687,6 +689,7 @@ void Unit::_Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SO
resourceGainTimer[4]=2;
}break;
}
resourceGainIcons.push_back({IMAGES[RESOURCE].get(),attachedPoint.lock()->type,GetPos()});
}
}
@ -966,4 +969,8 @@ void Unit::SaveMemory(){
bool Unit::IsPlatform(){
return isPlatform&&attachedPoint.expired()&&buildTime<=0;
}
bool Unit::IsAttached(){
return !attachedPoint.expired();
}

@ -71,7 +71,7 @@ public:
bool GhostInFogOfWar();
void HideGhost();
vf2d GetGhostPos();
void _Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::unique_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer);
void _Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::unique_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer,std::vector<ResourceGainIcon>&resourceGainIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
bool IsMoveable();
void DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
bool CanInteractWithEnemies();
@ -96,6 +96,7 @@ public:
bool IsGuarded();
void SaveMemory();
bool IsPlatform();
bool IsAttached();
Marker health={};
Marker range={};
Marker atkSpd={};

@ -65,52 +65,64 @@ void VirusAttack::InitializeImages(){
void VirusAttack::InitializeLevelData(){
#pragma region Stage 1
//Stage 1 data.
levelData[STAGE1].size={64,64};
levelData[STAGE1].bgm=Sound::BOSS2;
levelData[STAGE1].player_starting_resources={50,50,50,50,50};
levelData[STAGE1].enemy_starting_resources={0,0,0,0,0};
{
std::vector<UnitData>&units=levelData[STAGE1].unitPlacement;
std::vector<CPData>&collectionPoints=levelData[STAGE1].cpPlacement;
units.push_back({UnitType::LeftShifter,vf2d{128,128},true});
units.push_back({UnitType::RightShifter,vf2d{129,129},true});
units.push_back({UnitType::BitRestorer,vf2d{130,130},true});
units.push_back({UnitType::BitRestorer,vf2d{130,140},true});
units.push_back({UnitType::MemorySwapper,vf2d{131,131},true});
units.push_back({UnitType::Corrupter,vf2d{132,132},true});
units.push_back({UnitType::MemoryAllocator,vf2d{133,133},true});
units.push_back({UnitType::RAMBank,vf2d{134,134},true});
units.push_back({UnitType::MemoryGuard,vf2d{200,134},true});
for(int i=0;i<5;i++){
collectionPoints.push_back({vf2d{32.f+48*i,32.f},0,MemoryType(i)});
collectionPoints.push_back({vf2d{32.f,32.f+48*i},-PI/2,MemoryType(i)});
}
//Stage 1 data.
LevelName stage=STAGE1;
levelData[stage].cameraStart={96,96};
levelData[stage].worldZoom={1,1};
levelData[stage].levelColor=DARK_RED;
levelData[stage].size={64,64};
levelData[stage].bgm=Sound::BOSS2;
levelData[stage].player_starting_resources={50,50,50,50,50};
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::RightShifter,vf2d{129,129},true});
units.push_back({UnitType::BitRestorer,vf2d{130,130},true});
units.push_back({UnitType::BitRestorer,vf2d{130,140},true});
units.push_back({UnitType::MemorySwapper,vf2d{131,131},true});
units.push_back({UnitType::Corrupter,vf2d{132,132},true});
units.push_back({UnitType::MemoryAllocator,vf2d{133,133},true});
units.push_back({UnitType::RAMBank,vf2d{134,134},true});
units.push_back({UnitType::MemoryGuard,vf2d{200,134},true});
for(int i=0;i<5;i++){
collectionPoints.push_back({vf2d{32.f+48*i,32.f},0,MemoryType(i)});
collectionPoints.push_back({vf2d{32.f,32.f+48*i},-PI/2,MemoryType(i)});
}
units.push_back({UnitType::RAMBank,vf2d{1200,1200},false});
units.push_back({UnitType::RAMBank,vf2d{1200,1200},false});
units.push_back({UnitType::RightShifter,vf2d{1260,1200},false});
units.push_back({UnitType::RightShifter,vf2d{360,300},false});
units.push_back({UnitType::RightShifter,vf2d{361,300},false});
units.push_back({UnitType::RightShifter,vf2d{1260,1200},false});
units.push_back({UnitType::RightShifter,vf2d{360,300},false});
units.push_back({UnitType::RightShifter,vf2d{361,300},false});
}
}
#pragma endregion
#pragma region Stage 2
//Stage 2 data.
levelData[STAGE2].size={16,16};
levelData[STAGE2].bgm=Sound::COSMOS;
levelData[STAGE2].player_starting_resources={10,10,10,10,10};
levelData[STAGE2].enemy_starting_resources={0,0,0,0,0};
{
std::vector<UnitData>&units=levelData[STAGE2].unitPlacement;
std::vector<CPData>&collectionPoints=levelData[STAGE2].cpPlacement;
units.push_back({UnitType::RAMBank,vf2d{134,134},true});
units.push_back({UnitType::RAMBank,vf2d{1200,1200},false});
}
//Stage 2 data.
LevelName stage=STAGE2;
levelData[stage].cameraStart={96,96};
levelData[stage].worldZoom={1,1};
levelData[stage].size={16,16};
levelData[stage].levelColor=DARK_GREEN;
levelData[stage].bgm=Sound::COSMOS;
levelData[stage].player_starting_resources={10,10,10,10,10};
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{134,134},true});
units.push_back({UnitType::RAMBank,vf2d{1200,1200},false});
}
}
#pragma endregion
}
@ -203,6 +215,8 @@ void VirusAttack::LoadLevel(LevelName level){
for(auto&cp:selectedLevel.cpPlacement){
collectionPoints.push_back(std::make_unique<CollectionPoint>(this,cp.pos,cp.rot,*IMAGES[MEMORY_COLLECTION_POINT],cp.type));
}
randomBackgroundOffset={util::random(128),util::random(128)};
}
void VirusAttack::InitializeGUIs(){
@ -471,11 +485,35 @@ void VirusAttack::DrawMinimap(){
SetDrawTarget(IMAGES[MINIMAP_OUTLINE]->Sprite());
Clear(BLANK);
DrawRect((game.GetWorldOffset()/worldPixelSize*64),viewingTilesPct*64/game.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));
FillRect(u->GetGhostPos()/worldPixelSize*64-squareSize,squareSize*2,u->IsFriendly()?GREEN:RED);
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);
@ -647,7 +685,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){
}
}
u->AttemptAttack(u,closestUnit,units,debuffIcons,IMAGES);
u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer);
u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits,resourceGainTimer,resourceGainIcons,IMAGES);
}
std::erase_if(units,[&](std::shared_ptr<Unit>u){
@ -666,7 +704,8 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){
queuedUnits.clear();
game.DrawPartialDecal({0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},WORLD_SIZE*CONSTANT::TILE_SIZE,DARK_GREEN);
DrawPartialDecal({0,0},GetScreenSize(),IMAGES[MATRIX]->Decal(),randomBackgroundOffset,{32,32},Pixel{currentLevel->levelColor.r,currentLevel->levelColor.g,currentLevel->levelColor.b,164}/2);
game.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,game,IMAGES);
@ -699,7 +738,13 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){
icon.Draw(game);
}
for(ResourceGainIcon&icon:resourceGainIcons){
icon.Update(fElapsedTime);
icon.Draw(game);
}
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(game,IMAGES);
@ -765,7 +810,7 @@ void VirusAttack::RenderFogOfWar(){
for(int y=game.GetTopLeftTile().y/96-1;y<=game.GetBottomRightTile().y/96+1;y++){
for(int x=game.GetTopLeftTile().x/96-1;x<=game.GetBottomRightTile().x/96+1;x++){
if(TileManager::visibleTiles.count(vi2d{x,y})==0){
if(x>=0&&y>=0&&x<=WORLD_SIZE.x*CONSTANT::TILE_SIZE.x&&y<=WORLD_SIZE.y*CONSTANT::TILE_SIZE.y){
if(x>=0&&y>=0&&x<WORLD_SIZE.x/4&&y<WORLD_SIZE.y/4){
game.FillRectDecal(vf2d{float(x),float(y)}*96,{96,96},{0,0,0,128});
}
}

@ -34,6 +34,7 @@ private:
std::vector<std::shared_ptr<CollectionPoint>>collectionPoints;
std::vector<std::unique_ptr<DeathAnimation>>deathAnimations;
std::vector<DebuffIcon>debuffIcons;
std::vector<ResourceGainIcon>resourceGainIcons;
std::map<Image,std::unique_ptr<Renderable>>IMAGES;
std::map<Sound,std::unique_ptr<Audio>>SOUNDS;
@ -69,6 +70,8 @@ private:
std::vector<Letter>activeLetters;
std::array<float,5>resourceGainTimer={0};
vf2d randomBackgroundOffset;
vf2d startingDragPos=CONSTANT::UNSELECTED;
void HandleDraggingSelection();
void DrawSelectionRectangle();

@ -179,6 +179,7 @@ namespace olc
void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE);
// Draws a multiline string as a decal, with tiniting and scaling
void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
void DrawShadowStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col=olc::WHITE, const olc::Pixel shadowCol=olc::BLACK, const olc::vf2d & scale={1,1}, const float shadowSizeFactor=1);
void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
// Draws a single shaded filled rectangle as a decal
void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE);
@ -627,6 +628,11 @@ namespace olc
pge->DrawStringDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel);
}
void TransformedView::DrawShadowStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::Pixel shadowCol, const olc::vf2d & scale, const float shadowSizeFactor)
{
pge->DrawShadowStringDecal(WorldToScreen(pos), sText, col, shadowCol, scale * m_vWorldScale * m_vRecipPixel, shadowSizeFactor);
}
void TransformedView::DrawStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale )
{
pge->DrawStringPropDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel);

Loading…
Cancel
Save