Compare commits

...

33 Commits

Author SHA1 Message Date
sigonasr2 00fddea7d4 Fix the eyes... 1 year ago
sigonasr2 22c2c93126 Fix Audio issue with nan positions. Enemies can squeeze through their buildings. 1 year ago
sigonasr2 25b1e808a1 When game is beaten, you should load level 1 again, not the final level. 1 year ago
sigonasr2 822d52f92d Fix clear condition not occuring because of out-of-bounds enemies. 1 year ago
sigonasr2 4ec15f42a2 Change resource management AI behavior. 1 year ago
sigonasr2 d0a572c4fe Fix AI attacking each other. Also easy mode had infinite resources.. 1 year ago
sigonasr2 f63c2b00ca Collection Point AI fix. 1 year ago
sigonasr2 020c15bcc3 Collision boundary teleport fix. 1 year ago
sigonasr2 8b17d9bcbd We shouldn't mess with allocators that already are trying to collect resources. 1 year ago
sigonasr2 07c1a841d4 Whoops. Turn off that dang flashing bar. Also enemy units can only build to the memory limit.... As the rules are supposed to be. 1 year ago
sigonasr2 a034845557 Attached visual indicator update. 1 year ago
sigonasr2 3704c1e18c Final changes. Show timer as hh:mm:ss, fix tutorial bug using AI routine, fix bug enemy units attacking themselves. 1 year ago
sigonasr2 032801f3e8 audio speed argument bug. 1 year ago
sigonasr2 4ca649c2b7 exit game button pls. 1 year ago
sigonasr2 1a07786e7a Fix minor bugs and levels. Ready to go. Final post-fix feature build. 1 year ago
sigonasr2 a4439afc3f Virus Attack finalizing 1 year ago
sigonasr2 0b2b51c70c Add in ability for enemies to help other enemies. 1 year ago
sigonasr2 ca3f00a924 Rudimentary AI. 1 year ago
sigonasr2 1801f82248 Add in death sounds. 1 year ago
sigonasr2 90a2b5c562 Music/SE/no sounds controls. 1 year ago
sigonasr2 10bbb07894 Add in sound effects. 1 year ago
sigonasr2 bb33e8a8cd Stage 1 and 2 completed. 1 year ago
sigonasr2 34b32d809b Level transitions. 1 year ago
sigonasr2 7fd6cf677e Setup stages and finally cleared out memory issues. 1 year ago
sigonasr2 64f6b44994 Add in Scenario framework. 1 year ago
sigonasr2 12a21881e1 Added restart button QoL 1 year ago
sigonasr2 7188e6541e It stopped happening. I don't know why, but I don't care right now. We go. 1 year ago
sigonasr2 2b36a0cc9e Minor corrections as we find them. 1 year ago
sigonasr2 62f5fe938e ??? 1 year ago
sigonasr2 7e2bf32734 Title screen fancy effects added 1 year ago
sigonasr2 2d63b9c5cc Implement Game State, transparent button, transparent image button, scenarios 2-8, bugfixes. 1 year ago
sigonasr2 f840213233 Scenario 1 implemented. 1 year ago
sigonasr2 7e63a0a875 Support for text dialog, audio handling, and click to continue support. 1 year ago
  1. 5
      .gitignore
  2. 2
      olcCodeJam2023Entry/CollectionPoint.h
  3. 2
      olcCodeJam2023Entry/Constant.cpp
  4. 2
      olcCodeJam2023Entry/Constant.h
  5. 10
      olcCodeJam2023Entry/GameFlags.h
  6. 9
      olcCodeJam2023Entry/GameState.h
  7. 5
      olcCodeJam2023Entry/Image.h
  8. 17
      olcCodeJam2023Entry/Info.txt
  9. 8
      olcCodeJam2023Entry/Level.h
  10. 7
      olcCodeJam2023Entry/Memory.h
  11. 838
      olcCodeJam2023Entry/Scenario.cpp
  12. 116
      olcCodeJam2023Entry/Scenario.h
  13. 35
      olcCodeJam2023Entry/Sound.h
  14. 98
      olcCodeJam2023Entry/Textbox.cpp
  15. 16
      olcCodeJam2023Entry/Textbox.h
  16. 337
      olcCodeJam2023Entry/Unit.cpp
  17. 127
      olcCodeJam2023Entry/Unit.h
  18. 1229
      olcCodeJam2023Entry/VirusAttack.cpp
  19. 61
      olcCodeJam2023Entry/VirusAttack.h
  20. BIN
      olcCodeJam2023Entry/assets/ending.png
  21. BIN
      olcCodeJam2023Entry/assets/hooded_figure.png
  22. BIN
      olcCodeJam2023Entry/assets/restart.png
  23. BIN
      olcCodeJam2023Entry/assets/restartHover.png
  24. BIN
      olcCodeJam2023Entry/assets/round_bar.png
  25. BIN
      olcCodeJam2023Entry/assets/shieldbubble.png
  26. BIN
      olcCodeJam2023Entry/assets/spook_hooded_figure.png
  27. 2
      olcCodeJam2023Entry/emscripten_build.ps1
  28. 11
      olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj
  29. 9
      olcCodeJam2023Entry/olcCodeJam2023Entry.vcxproj.filters
  30. 24
      olcCodeJam2023Entry/olcPGEX_AudioSource.h
  31. 120
      olcCodeJam2023Entry/olcPGEX_QuickGUI.h
  32. 4
      olcCodeJam2023Entry/olcPGEX_SplashScreen.h
  33. 6
      olcCodeJam2023Entry/olcPGEX_TransformedView.h
  34. 14
      olcCodeJam2023Entry/olcPixelGameEngine.h
  35. 6
      olcCodeJam2023Entry/olcUTIL_Camera2D.h
  36. BIN
      olcCodeJam2023Entry/pge.data
  37. 1297
      olcCodeJam2023Entry/pge.html
  38. 11133
      olcCodeJam2023Entry/pge.js
  39. BIN
      olcCodeJam2023Entry/pge.wasm

5
.gitignore vendored

@ -11,6 +11,9 @@
*.sln.docstates
*.wav
Windows
Emscripten
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@ -363,3 +366,5 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
*.mp3
*.zip
/olcCodeJam2023Entry/VirusAttack.exe

@ -2,7 +2,7 @@
#include "olcPixelGameEngine.h"
#include "MemoryType.h"
class Unit;
struct Unit;
class CollectionPoint{
public:

@ -39,3 +39,5 @@ std::string CONSTANT::MEMORY_ALLOCATOR_BOX_HEADER_STRING="Memory Allocator";
Pixel CONSTANT::INCREASE_VALUE_COLOR={7, 223, 247};
Pixel CONSTANT::DECREASE_VALUE_COLOR={201, 30, 30};
float CONSTANT::RESTART_BUTTON_HOLD_TIME=2.5;

@ -43,4 +43,6 @@ public:
static Pixel INCREASE_VALUE_COLOR;
static Pixel DECREASE_VALUE_COLOR;
static float RESTART_BUTTON_HOLD_TIME;
};

@ -0,0 +1,10 @@
#pragma once
struct GameFlags{
bool unitMetersGreyedOut=true;//If true, all but health meters show up as dark grey.
bool playerInControl=false;
bool limitedBuildOptions=false;
bool guideEnabled=false;
bool flashMemoryBar=false;
int difficulty=1; //0=Easy, 1=Normal, 2=Hard
};

@ -0,0 +1,9 @@
#pragma once
enum class GameState{
MAIN_MENU,
GAMEPLAY,
COMPLETED,
CREDITS
};

@ -40,5 +40,10 @@ enum Image{
GUIDE,
ROUND_BAR,
SEGMENT_BAR,
HOODED_FIGURE,
SPOOK_HOODED_FIGURE,
RESTART,
RESTART_HOVER,
SHIELD_BUBBLE,
};

@ -39,7 +39,7 @@ Fake allies the narrator forgot to switch over
Day 9 Sounds/Music/Menus - Timer (Speedrun) Difficulty Selection
Ending...Shows Four Seasons of Loneliness boss zoom out...
Easy Difficulty: AI generate no new resources.
Easy Difficulty: AI generate no new resources. Start with 100 of each.
Normal Difficulty: AI generates resources at normal rate.
Hard Difficulty: AI generates resources at x4 rate.
@ -56,7 +56,7 @@ Stage 1:
The yellow bar represent a unit's Health memory allocation. Make sure there's always at least 1 bit of it.
(Simulate dragging over unit and selection)
Highlight over your target unit and then select a target location via right-click.
Drag over your target unit and then select a target location via right-click.
That should be all you need for now. I'll be back after my coffee break.
@ -102,7 +102,8 @@ Stage 4:
[Pan over to a collection point]
But we can collect bits from the system using these collection points.
Simply bring over any unit to these and attach them to it. They will start providing you with system resources to make what you need.
(After attaching a unit to a collection point...)
Remember that the system has limited memory available. You'll always be fighting for free space from the system.
(After attaching two units to collection points...)
2 Left shifters wander into the area.
[Pan over to the RAM bank]
An ambush...? I, WHAT? -- THIS IS NOT-
@ -128,6 +129,9 @@ Stage 8:
(New Scenario Objective:
-Defeat all enemy units)
Create a Restart feature.
Distribution of Collection Points:
HEALTH 60
ATKSPD 21
@ -148,3 +152,10 @@ Space - Gravity (Ambient 1)
1 Glorious Venture (Ending theme?)
Credits
Finish Scenarios (End condition for the game)
Finish up main menu stuff (including credits)
AI stuff

@ -3,8 +3,6 @@
#include "Unit.h"
#include "CollectionPoint.h"
class Scenario;
enum LevelName{
STAGE1,
STAGE2,
@ -14,6 +12,7 @@ enum LevelName{
STAGE6,
STAGE7,
STAGE8,
FINISH,
};
struct UnitData{
@ -33,13 +32,14 @@ struct CPData{
//Large: 1280
struct Level{
LevelName name=STAGE1;
vi2d size={1,1};
Resources player_starting_resources;
Resources enemy_starting_resources;
std::vector<UnitData>unitPlacement;
std::vector<CPData>cpPlacement;
Sound bgm=Sound::COSMOS;
Scenario*scenario;
Sound::Sound bgm=Sound::COSMOS;
int scenarioIndex=0;
vf2d cameraStart={96,96};
vf2d worldZoom={1,1};
Pixel levelColor=DARK_GREEN;

@ -0,0 +1,7 @@
#pragma once
#include "MemoryType.h"
struct Memory{
MemoryType type;
int size;
};

@ -1,22 +1,838 @@
#include "Scenario.h"
#include "TileManager.h"
#include "olcUTIL_Geometry2D.h"
Scenario::Scenario(VirusAttack*game)
:game(game){}
void Scenario::_Update(){
Update();
}
void Scenario::_Draw(){
Draw();
Scenario::Scenario(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:units(units),IMAGES(IMAGES),SOUNDS(SOUNDS),objective(objective),game(game),flags(flags){}
Scenario::~Scenario(){};
void Scenario::_Start(){
state=0;
camera=utils::Camera2D{game.GetPGE()->GetScreenSize(),game.GetWorldOffset()};
camera.SetLazyFollowRate(2);
camera.SetMode(utils::Camera2D::Mode::LazyFollow);
targetPos={96,96};
box.SetVisible(false);
initialWaitTime=3;
camera.SetTarget(targetPos);
missionCompletedTimer=0;
transitionToNextLevel=false;
setupEasyMode=false;
Start();
}
void Scenario::Start(){};
void Scenario::_Update(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS){
initialWaitTime=std::max(0.f,initialWaitTime-game.GetPGE()->GetElapsedTime());
missionFinishWaitTime=std::max(0.f,missionFinishWaitTime-game.GetPGE()->GetElapsedTime());
smallTimePass=std::min(1.f,smallTimePass+game.GetPGE()->GetElapsedTime());
if(flags.playerInControl){
smallTimePass=0;
}
if(missionCompleted){
missionCompletedTimer+=game.GetPGE()->GetElapsedTime();
} else {
missionCompleted=MissionCompleted();
}
if(flags.playerInControl){
RunAI(enemy_resources,collectionPoints,availableMemory,queuedUnits,SOUNDS);
}
if(initialWaitTime==0){
Update();
}
};
void Scenario::RunAI(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS){
if(!flags.guideEnabled||flags.limitedBuildOptions||flags.unitMetersGreyedOut)return; //We don't enable advanced AI during tutorials.
Stage1::Stage1(VirusAttack*game)
:Scenario(game){}
if(!setupEasyMode&&flags.difficulty==0){
enemy_resources={100,100,100,100,100};
setupEasyMode=true;
}
attackTimer=std::max(0.f,attackTimer-game.GetPGE()->GetElapsedTime());
unitBuildTimer=std::max(0.f,unitBuildTimer-game.GetPGE()->GetElapsedTime());
std::weak_ptr<Unit>baseOfOperations;
std::weak_ptr<Unit>enemyBaseOfOperations;
for(auto&u:units){
if(!u->IsFriendly()&&u->IsRAMBank()){
baseOfOperations=u;
break;
}
}
for(auto&u:units){
if(u->IsFriendly()&&u->IsRAMBank()){
enemyBaseOfOperations=u;
break;
}
}
if(baseOfOperations.expired()){
for(auto&u:units){
if(!u->IsFriendly()){
baseOfOperations=u;
break;
}
}
}
//See if there are collectors, if so send memory allocator units towards them.
if(!baseOfOperations.expired()){
std::sort(collectionPoints.begin(),collectionPoints.end(),[&](std::shared_ptr<CollectionPoint>cp1,std::shared_ptr<CollectionPoint>cp2){
geom2d::line<float>toCP1={cp1->pos,baseOfOperations.lock()->GetPos()};
geom2d::line<float>toCP2={cp2->pos,baseOfOperations.lock()->GetPos()};
return toCP1.length()<toCP2.length();});
}
int maxOfResources=enemy_resources.health;
maxOfResources=std::max(maxOfResources,enemy_resources.atkSpd);
maxOfResources=std::max(maxOfResources,enemy_resources.moveSpd);
maxOfResources=std::max(maxOfResources,enemy_resources.procedure);
maxOfResources=std::max(maxOfResources,enemy_resources.range);
if(maxOfResources<10){
for(auto&cp:collectionPoints){
if(cp->attachedUnit.expired()){
if(cpCheckTimer.count(cp.get())==0||cpCheckTimer[cp.get()]<=0){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsAllocator()&&u->attachTarget.expired()){
//Tell this unit to move towards that collection point.
u->SetTargetCollectionPoint(cp,u);
break;
}
}
//Hasn't been checked recently.
cpCheckTimer[cp.get()]=60;
}
}
}
}
for(auto&key:cpCheckTimer){
cpCheckTimer[key.first]=std::max(0.0f,cpCheckTimer[key.first]-game.GetPGE()->GetElapsedTime());
}
int memoryAllocatorCount=0;
for(auto&u:units){
if(!u->IsFriendly()&&u->IsAllocator()){
memoryAllocatorCount++;
}
}
if(memoryAllocatorCount<3){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsRAMBank()){
AttemptBuild(UnitType::MemoryAllocator,u->GetPos(),MemoryAllocator::resourceCost,enemy_resources,availableMemory,queuedUnits);
}
}
}
//Randomly turn memory allocators into other units.
if(unitBuildTimer==0){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsAllocator()&&u->attachTarget.expired()){
std::array<UnitType,10>unitChoiceList={UnitType::LeftShifter,UnitType::LeftShifter,UnitType::RightShifter,UnitType::RightShifter,
UnitType::Corrupter,UnitType::MemorySwapper,UnitType::BitRestorer,UnitType::BitRestorer,UnitType::_Platform,UnitType::Corrupter};
std::array<std::vector<Memory>,10>unitResourceCostList={LeftShifter::resourceCost,LeftShifter::resourceCost,RightShifter::resourceCost,RightShifter::resourceCost,
Corrupter::resourceCost,MemorySwapper::resourceCost,BitRestorer::resourceCost,BitRestorer::resourceCost,_Platform::resourceCost,Corrupter::resourceCost};
int randomIndex=rand()%unitChoiceList.size();
UnitType buildUnit=unitChoiceList[randomIndex];
void Stage1::Update(){
int totalCost=0;
for(int i=0;i<unitResourceCostList[randomIndex].size();i++){
totalCost+=unitResourceCostList[randomIndex][i].size;
}
if(totalCost<=availableMemory){
#define Build(type) \
case UnitType::type:{ \
u->SetBuildUnit(8,std::make_shared<type>(game.GetPGE(),u->GetPos(),IMAGES,false),SOUNDS); \
}break;
switch(buildUnit){
Build(LeftShifter)
Build(RightShifter)
Build(BitRestorer)
Build(_Platform)
Build(Corrupter)
Build(MemorySwapper)
}
if(enemy_resources.health>0){enemy_resources.health=std::max(0,enemy_resources.health-totalCost);}else
if(enemy_resources.atkSpd>0){enemy_resources.atkSpd=std::max(0,enemy_resources.atkSpd-totalCost);}else
if(enemy_resources.moveSpd>0){enemy_resources.moveSpd=std::max(0,enemy_resources.moveSpd-totalCost);}else
if(enemy_resources.range>0){enemy_resources.range=std::max(0,enemy_resources.range-totalCost);}else
{enemy_resources.procedure=std::max(0,enemy_resources.procedure-totalCost);
}
availableMemory-=totalCost;
}
}
if(!u->IsFriendly()&&u->IsPlatform()){
std::array<UnitType,7>unitChoiceList={UnitType::RAMBank,UnitType::Refresher,UnitType::Refresher,UnitType::Turret,
UnitType::Turret,UnitType::Turret,UnitType::MemoryGuard};
std::array<std::vector<Memory>,7>unitResourceCostList={RAMBank::resourceCost,Refresher::resourceCost,Refresher::resourceCost,Turret::resourceCost,
Turret::resourceCost,Turret::resourceCost,MemoryGuard::resourceCost};
int randomIndex=rand()%unitChoiceList.size();
UnitType buildUnit=unitChoiceList[randomIndex];
int totalCost=0;
for(int i=0;i<unitResourceCostList[randomIndex].size();i++){
totalCost+=unitResourceCostList[randomIndex][i].size;
}
if(totalCost<=availableMemory){
#define Build(type) \
case UnitType::type:{ \
u->SetBuildUnit(8,std::make_shared<type>(game.GetPGE(),u->GetPos(),IMAGES,false),SOUNDS); \
}break;
switch(buildUnit){
Build(RAMBank)
Build(Refresher)
Build(Turret)
Build(MemoryGuard)
}
if(enemy_resources.health>0){enemy_resources.health=std::max(0,enemy_resources.health-totalCost);}else
if(enemy_resources.atkSpd>0){enemy_resources.atkSpd=std::max(0,enemy_resources.atkSpd-totalCost);}else
if(enemy_resources.moveSpd>0){enemy_resources.moveSpd=std::max(0,enemy_resources.moveSpd-totalCost);}else
if(enemy_resources.range>0){enemy_resources.range=std::max(0,enemy_resources.range-totalCost);}else
{enemy_resources.procedure=std::max(0,enemy_resources.procedure-totalCost);
}
availableMemory-=totalCost;
}
}
switch(flags.difficulty){
case 0:{
unitBuildTimer=120;
}break;
case 1:{
unitBuildTimer=60;
}break;
case 2:{
unitBuildTimer=10;
}break;
}
}
}
if(attackTimer==0){
if(!enemyBaseOfOperations.expired()){
for(auto&u:units){
if(!u->IsFriendly()&&rand()%3==0){
if(u->CanInteractWithEnemies()&&!u->IsAllocator()&&u->CanMove()){
u->SetTargetUnit(enemyBaseOfOperations);
}
}
}
for(auto&u:units){
if(!u->IsFriendly()&&u->GetCurrentTarget().expired()&&u->CanInteractWithAllies()){
if(rand()%5==0){
u->SetTargetLocation(enemyBaseOfOperations.lock()->GetPos());
}
}
}
}
switch(flags.difficulty){
case 0:{
attackTimer=999;
}break;
case 1:{
attackTimer=300;
}break;
case 2:{
attackTimer=120;
}break;
}
}
}
/*
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); \
*/
bool Scenario::AttemptBuild(UnitType unit,vf2d pos,std::vector<Memory>&resourceCost,Resources&enemy_resources,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits){
int enemyTotalResources=enemy_resources.atkSpd+enemy_resources.health+enemy_resources.moveSpd+enemy_resources.procedure+enemy_resources.range;
int totalCost=0;
for(int i=0;i<resourceCost.size();i++){
totalCost+=resourceCost[i].size;
}
if(totalCost>availableMemory)return false;
if(enemyTotalResources>=totalCost){
if(enemy_resources.health>0){enemy_resources.health=std::max(0,enemy_resources.health-totalCost);}else
if(enemy_resources.atkSpd>0){enemy_resources.atkSpd=std::max(0,enemy_resources.atkSpd-totalCost);}else
if(enemy_resources.moveSpd>0){enemy_resources.moveSpd=std::max(0,enemy_resources.moveSpd-totalCost);}else
if(enemy_resources.range>0){enemy_resources.range=std::max(0,enemy_resources.range-totalCost);}else
{enemy_resources.procedure=std::max(0,enemy_resources.procedure-totalCost);}
#define TranslateUnit(type) \
case UnitType::type:{ \
queuedUnits.emplace_back(std::make_shared<type>(game.GetPGE(),pos,IMAGES,false)); \
}break;
switch(unit){
TranslateUnit(MemoryAllocator)
TranslateUnit(LeftShifter)
TranslateUnit(RightShifter)
TranslateUnit(BitRestorer)
TranslateUnit(MemorySwapper)
TranslateUnit(Corrupter)
TranslateUnit(RAMBank)
TranslateUnit(MemoryGuard)
TranslateUnit(Refresher)
TranslateUnit(Turret)
TranslateUnit(_Platform)
}
}
return true;
}
void Stage1::Draw(){
bool Scenario::MissionCompleted(){return false;}
void Scenario::Update(){};
void Scenario::Draw(){
if(objective.length()>0){
game.GetPGE()->DrawShadowStringDecal({4,24},"Objective:");
game.GetPGE()->DrawShadowStringDecal({6,36},objective);
game.GetPGE()->DrawShadowStringDecal({4,24},missionCompleted?"Objective Complete!":"Objective:",missionCompleted?GREEN:WHITE);
vf2d textSize=game.GetPGE()->GetTextSize(objective);
game.GetPGE()->DrawShadowStringDecal({6,36},objective,missionCompleted?GREEN:WHITE);
if(missionCompleted&&missionFinishWaitTime==0){
game.GetPGE()->FillRectDecal(vf2d{6,36}+vf2d{0,textSize.y/2-1},{textSize.x,3});
std::string continueText="< Press [Spacebar] to continue >";
vf2d textScale={2,3};
vf2d textSize=game.GetPGE()->GetTextSizeProp(continueText)*textScale;
game.GetPGE()->DrawShadowStringPropDecal(game.GetPGE()->GetScreenSize()/2-textSize/2+vf2d{0,72},continueText,{255,255,255,uint8_t(abs(sin(2*missionCompletedTimer))*255)},{0,0,0,uint8_t(abs(sin(2*missionCompletedTimer))*255)},textScale);
if(game.GetPGE()->GetKey(SPACE).bPressed){
transitionToNextLevel=true;
}
}
}
Resources temp={0,0,0,0,0};
box.UpdateAndDraw({24,64},game.GetPGE(),temp,IMAGES,0,0);
}
void Scenario::SetCameraTarget(vf2d pos,bool instant){
if(instant){camera.SetMode(utils::Camera2D::Mode::Simple);} else {camera.SetMode(utils::Camera2D::Mode::LazyFollow);}
targetPos=pos;
camera.SetTarget(targetPos);
camera.Update(game.GetPGE()->GetElapsedTime());
game.SetWorldOffset(camera.GetViewPosition());
}
void Scenario::SetObjective(std::string objective){
this->objective=objective;
}
void Scenario::RevealTiles(vf2d pos){
for(int y=-1;y<=1;y++){
for(int x=-1;x<=1;x++){
vi2d basePos={int(pos.x+x*96),int(pos.y+y*96)};
TileManager::visibleTiles[{basePos.x/96,basePos.y/96}]=30;
}
}
}
Stage1::Stage1(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage1::Start(){
flags.unitMetersGreyedOut=true;
flags.playerInControl=false;
nextLevel=LevelName::STAGE2;
};
void Scenario::DisplayBox(std::string text,bool scaryHoodedFigure){
if(smallTimePass==1){
box.Initialize(text,{24,64},"",scaryHoodedFigure?IMAGES[SPOOK_HOODED_FIGURE].get():IMAGES[HOODED_FIGURE].get(),{378,28},SOUNDS[Sound::VOICEOVER].get());
}
}
void Stage1::Update(){
switch(state){
case 0:{
DisplayBox("Hello Hacker, thank you for taking on this request for me.");
if(box.bPressed){
state=1;
}
}break;
case 1:{
DisplayBox("It appears we have no time to waste, many sectors are already infected and the virus spread will just keep getting worse.");
if(box.bPressed){
state=2;
SOUNDS[Sound::PING]->PlayCentered();
RevealTiles({320,320});
}
}break;
case 2:{
SetCameraTarget({320,320});
if(camera.ReachedTarget()){
state=3;
}
}break;
case 3:{
DisplayBox("Your mission is to take out all the RAM banks from the system, this will stop any further creation and spread of viruses.");
if(box.bPressed){
state=4;
}
}break;
case 4:{
SetCameraTarget({128,128});
if(camera.ReachedTarget()){
state=5;
}
}break;
case 5:{
DisplayBox("The yellow bars represent units' allocated Health memory. Take out the enemies' and make sure you always have at least 1 bit of it.");
if(box.bPressed){
state=6;
}
}break;
case 6:{
DisplayBox("Drag over your target unit and then select a target location via right-click.");
if(box.bPressed){
state=7;
}
}break;
case 7:{
SetObjective("Defeat the RAM bank");
DisplayBox("That should be all you need for now. I'll be back after my coffee break.");
if(box.bPressed){
state=8;
box.SetVisible(false);
flags.playerInControl=true;
}
}break;
case 8:{
}break;
}
};
bool Stage1::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsRAMBank()){
return false;
}
}
return true;
}
Stage2::Stage2(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage2::Start(){
flags.playerInControl=false;
flags.limitedBuildOptions=true;
flags.flashMemoryBar=false;
SetCameraTarget({7*24,10*24},true);
nextLevel=LevelName::STAGE3;
};
void Stage2::Update(){
switch(state){
case 0:{
DisplayBox("You took care of that sector flawlessly Hacker, this next one needs a bit more hand-holding.");
if(box.bPressed){
state=1;
}
}break;
case 1:{
SetObjective("Create a RAM bank.");
DisplayBox("We have analyzed the data from the RAM bank and can now create one. Go ahead and select the Platform here and construct one.");
if(box.bPressed){
state=2;
box.SetVisible(false);
flags.playerInControl=true;
}
}break;
case 2:{
for(auto&u:units){
if(u->IsRAMBank()&&u->IsFriendly()){
state=3;
flags.playerInControl=false;
SetObjective("");
break;
}
}
}break;
case 3:{
DisplayBox("Excellent, each RAM bank has the capability to allocate memory into the system. See that indicator down below?");
flags.flashMemoryBar=true;
if(box.bPressed){
state=4;
}
}break;
case 4:{
DisplayBox("This sector lets us allocate 30 bytes of RAM. That's 240 bits for the savvy folks out there.");
if(box.bPressed){
state=5;
flags.flashMemoryBar=false;
}
}break;
case 5:{
DisplayBox("Some of it has already been used up by our RAM bank and other system resources... ");
if(box.bPressed){
state=6;
}
}break;
case 6:{
SetObjective("Build a Memory Allocator.");
DisplayBox("To allocate 5 bits, select the RAM bank and click the Memory Allocator button.\n\nGive it a try now.");
if(box.bPressed){
state=7;
box.SetVisible(false);
flags.playerInControl=true;
}
}break;
case 7:{
for(auto&u:units){
if(u->IsAllocator()&&u->IsFriendly()){
state=8;
flags.playerInControl=false;
SetObjective("");
break;
}
}
}break;
case 8:{
SetObjective("Build a Left or Right Bit Shifter.");
DisplayBox("Now select the memory allocator and let's make a Shifter unit.");
if(box.bPressed){
state=9;
box.SetVisible(false);
flags.playerInControl=true;
}
}break;
case 9:{
for(auto&u:units){
if(!u->IsAllocator()&&!u->IsRAMBank()&&u->IsFriendly()){
state=10;
flags.playerInControl=false;
SetObjective("");
break;
}
}
}break;
case 10:{
DisplayBox("The memory shifters will be your primary way to delete memory from units.");
if(box.bPressed){
state=11;
SOUNDS[Sound::ALARM]->PlayCentered();
}
}break;
case 11:{
SetCameraTarget({22*24,23*24});
RevealTiles({22*24,23*24});
if(camera.ReachedTarget()){
state=12;
}
}break;
case 12:{
SetObjective("Defeat all enemy units.");
DisplayBox("I have detected viruses in the system again. Please eradicate them and free system resources.");
if(box.bPressed){
state=13;
flags.playerInControl=true;
box.SetVisible(false);
}
}break;
}
};
bool Stage2::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()){
return false;
}
}
return true;
}
Stage3::Stage3(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage3::Start(){
flags.playerInControl=false;
flags.unitMetersGreyedOut=true;
flags.guideEnabled=false;
flags.limitedBuildOptions=true;
SetCameraTarget({3*24,6*24},true);
oopsTimer=0.3;
nextLevel=LevelName::STAGE4;
};
void Stage3::Update(){
switch(state){
case 0:{
DisplayBox("I haven't touched on what the other meters on your units are, but they are important!");
if(box.bPressed){
SOUNDS[Sound::SWITCH]->PlayCentered();
flags.unitMetersGreyedOut=false;
state=1;
}
}break;
case 1:{
DisplayBox("The Blue bits indicates movement capabilities of a unit.");
if(box.bPressed){
state=2;
}
}break;
case 2:{
DisplayBox("The Green bits indicates the range of a unit.");
if(box.bPressed){
state=3;
}
}break;
case 3:{
DisplayBox("The Red bits are the attack speed bits.");
if(box.bPressed){
state=4;
}
}break;
case 4:{
DisplayBox("And Purple are the Procedure bits. Without these, your unit will fail to recall how to function.");
if(box.bPressed){
state=5;
}
}break;
case 5:{
DisplayBox("As units attack each other, their bits are going to get shuffled around, impeding their ability to perform.");
if(box.bPressed){
state=6;
}
}break;
case 6:{
DisplayBox("Your immediate goal is to always take out the Yellow bits but sometimes taking out other bits is important too.");
if(box.bPressed){
SOUNDS[Sound::SWITCH]->PlayCentered();
flags.guideEnabled=true;
state=7;
}
}break;
case 7:{
DisplayBox("I'll leave a guide by the map in case your memory betrays you.");
if(box.bPressed){
state=8;
}
}break;
case 8:{
SetObjective("Defeat all units");
DisplayBox("You now have access to more units as well. Do check them out!");
if(box.bPressed){
SetObjective("Defeat all units (Oops)");
state=9;
}
}break;
case 9:{
oopsTimer=std::max(0.f,oopsTimer-game.GetPGE()->GetElapsedTime());
if(oopsTimer==0){
SetObjective("Defeat all enemy units.");
state=10;
flags.limitedBuildOptions=false;
flags.playerInControl=true;
box.SetVisible(false);
}
}break;
case 10:{
}break;
}
};
bool Stage3::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()){
return false;
}
}
return true;
}
Stage4::Stage4(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage4::Start(){
nextLevel=LevelName::STAGE5;
flags.playerInControl=false;
flags.guideEnabled=true;
flags.limitedBuildOptions=false;
flags.unitMetersGreyedOut=false;
flags.flashMemoryBar=false;
SetCameraTarget({4*24,4*24},true);
};
void Stage4::Update(){
switch(state){
case 0:{
DisplayBox("Hacker, I have unfortunate news. I can't supply you with any more bits to construct things with.");
if(box.bPressed){
state=1;
}
}break;
case 1:{
DisplayBox("You've only got 3 health bits to start with this time. To allocate memory you always need at least 5 bits of memory.");
if(box.bPressed){
state=2;
}
}break;
case 2:{
SetCameraTarget({8*24,1*24});
if(camera.ReachedTarget()){
state=3;
}
}break;
case 3:{
DisplayBox("But we can collect bits from the system using these collection points.");
if(box.bPressed){
state=4;
}
}break;
case 4:{
DisplayBox("Simply bring over any unit to these and attach them to it. They will start providing you with system resources to make what you need.");
if(box.bPressed){
state=5;
}
}break;
case 5:{
flags.flashMemoryBar=true;
SetObjective("Setup units at collection points");
DisplayBox("Remember that the system has limited memory available. You'll always be fighting for free space from the system.");
if(box.bPressed){
state=6;
box.SetVisible(false);
flags.playerInControl=true;
flags.flashMemoryBar=false;
}
}break;
case 6:{
collectorsAttached=0;
for(auto&u:units){
if(u->IsAttached()){
collectorsAttached++;
}
}
if(collectorsAttached>=2){
std::shared_ptr<Unit>target;
for(auto&u:units){
if(u->IsRAMBank()){
target=u;
}
}
state=7;
SOUNDS[Sound::ALARM]->PlayCentered();
flags.playerInControl=false;
auto u1=std::make_shared<LeftShifter>(game.GetPGE(),vf2d{4*24,10*24},IMAGES,false);
auto u2=std::make_shared<LeftShifter>(game.GetPGE(),vf2d{4*24,10*24},IMAGES,false);
auto u3=std::make_shared<LeftShifter>(game.GetPGE(),vf2d{4*24,10*24},IMAGES,false);
units.push_back(u1);
units.push_back(u2);
units.push_back(u3);
u1->SetTargetUnit(target);
u2->SetTargetUnit(target);
u3->SetTargetUnit(target);
}
}break;
case 7:{
SetCameraTarget({4*24,4*24});
if(camera.ReachedTarget()){
state=8;
SOUNDS[Sound::WIND]->PlayCentered();
}
}break;
case 8:{
DisplayBox("An ambush...? I, WHAT? -- THIS IS NOT-");
if(box.bPressed){
state=9;
box.SetVisible(false);
nextLevelTimer=5;
}
}break;
case 9:{
nextLevelTimer=std::max(0.f,nextLevelTimer-game.GetPGE()->GetElapsedTime());
if(nextLevelTimer==0){
state=10;
}
}break;
case 10:{
transitionToNextLevel=true;
state=11;
}break;
}
};
bool Stage4::MissionCompleted(){
return false;
}
Stage5::Stage5(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage5::Start(){
SetCameraTarget({4*24,4*24},true);
flags.playerInControl=true;
SetObjective("Defeat all enemy RAM banks.");
nextLevel=LevelName::STAGE6;
};
void Stage5::Update(){
switch(state){
case 0:{
}break;
}
};
bool Stage5::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsRAMBank()){
return false;
}
}
return true;
}
Stage6::Stage6(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage6::Start(){
SetCameraTarget({4*24,4*24},true);
flags.playerInControl=true;
SetObjective("Defeat all enemy RAM banks.");
nextLevel=LevelName::STAGE7;
};
void Stage6::Update(){
switch(state){
case 0:{
flags.playerInControl=false;
DisplayBox("...");
if(box.bPressed){
flags.playerInControl=true;
box.SetVisible(false);
state=1;
}
}break;
}
};
bool Stage6::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()&&u->IsRAMBank()){
return false;
}
}
return true;
}
Stage7::Stage7(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage7::Start(){
SetCameraTarget({4*24,4*24},true);
flags.playerInControl=true;
SetObjective("Defeat all enemy units.");
nextLevel=LevelName::STAGE8;
};
void Stage7::Update(){
switch(state){
case 0:{
flags.playerInControl=false;
DisplayBox("I see you have a few new tricks up your sleeve, Hacker.",true);
if(box.bPressed){
state=1;
}
}break;
case 1:{
DisplayBox("Don't think it'll be that easy to get through this one...",true);
if(box.bPressed){
state=2;
flags.playerInControl=true;
box.SetVisible(false);
}
}break;
}
};
bool Stage7::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()){
return false;
}
}
return true;
}
Stage8::Stage8(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags)
:Scenario(units,IMAGES,SOUNDS,objective,game,flags){}
void Stage8::Start(){
SetCameraTarget({4*24,4*24},true);
flags.playerInControl=false;
SetObjective("Defeat all enemy units.");
nextLevel=LevelName::FINISH;
};
void Stage8::Update(){
switch(state){
case 0:{
DisplayBox("You need to cease all operations, you are causing more harm than good.",true);
if(box.bPressed){
state=1;
flags.playerInControl=true;
box.SetVisible(false);
}
}break;
}
};
bool Stage8::MissionCompleted(){
for(auto&u:units){
if(!u->IsFriendly()){
return false;
}
}
return true;
}

@ -1,20 +1,116 @@
#pragma once
#include "VirusAttack.h"
#include "olcUTIL_Camera2D.h"
#include "Textbox.h"
#include "Unit.h"
#include "olcPGEX_AudioSource.h"
#include "olcPGEX_TransformedView.h"
#include "GameFlags.h"
#include "Level.h"
class Scenario{
VirusAttack*game;
public:
Scenario(VirusAttack*game);
void _Update();
virtual void Update()=0;
void _Draw();
virtual void Draw()=0;
Scenario(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
virtual~Scenario();
void _Start();
void Draw();
virtual void Start();
void _Update(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool transitionToNextLevel=false;
LevelName nextLevel=LevelName::STAGE1;
void RunAI(Resources&enemy_resources,std::vector<std::shared_ptr<CollectionPoint>>&collectionPoints,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool setupEasyMode=false;
float attackTimer=120;
std::map<CollectionPoint*,float>cpCheckTimer;
bool AttemptBuild(UnitType unit,vf2d pos,std::vector<Memory>&resourceCost,Resources&enemy_resources,int availableMemory,std::vector<std::shared_ptr<Unit>>&queuedUnits);
protected:
void DisplayBox(std::string text,bool scaryHoodedFigure=false);
void SetCameraTarget(vf2d pos,bool instant=false);
void SetObjective(std::string objective);
void RevealTiles(vf2d pos);
virtual bool MissionCompleted();
virtual void Update();
int state=0;
utils::Camera2D camera;
vf2d targetPos;
Textbox box;
float initialWaitTime=3;
bool missionCompleted=false;
float missionFinishWaitTime=3;
float missionCompletedTimer=0;
float smallTimePass=0;
std::vector<std::shared_ptr<Unit>>&units;
std::vector<std::unique_ptr<Renderable>>&IMAGES;
std::vector<std::unique_ptr<Audio>>&SOUNDS;
GameFlags&flags;
std::string&objective;
TileTransformedView&game;
float unitBuildTimer=0;
};
class Stage1:public Scenario{
public:
Stage1(VirusAttack*game);
void Update()override;
void Draw()override;
Stage1(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage2:public Scenario{
public:
Stage2(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage3:public Scenario{
public:
float oopsTimer=0.3;
Stage3(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage4:public Scenario{
public:
Stage4(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
int collectorsAttached=0;
float nextLevelTimer=0;
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage5:public Scenario{
public:
Stage5(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage6:public Scenario{
public:
Stage6(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage7:public Scenario{
public:
Stage7(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};
class Stage8:public Scenario{
public:
Stage8(std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::string&objective,TileTransformedView&game,GameFlags&flags);
protected:
void Start();
void Update();
bool MissionCompleted();
};

@ -1,9 +1,30 @@
#pragma once
enum class Sound{
HUM,
GRAVITY,
COSMOS,
BOSS1,
BOSS2,
};
namespace Sound{
enum Sound:int{
HUM,
GRAVITY,
COSMOS,
BOSS1,
BOSS2,
VOICEOVER,
PING,
ALARM,
SWITCH,
HIT1,
HIT2,
HIT3,
BUTTONSELECT,
SMALLBUILD,
BIGBUILD,
HEAL,
REFRESHER,
TURRET,
MEMORY_GUARD,
SPAWN,
DEAD1,
DEAD2,
DEAD3,
WIND,
};
}

@ -4,7 +4,7 @@
Textbox::Textbox(){};
void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,vf2d maxSize,std::vector<Memory>resourceCost,float letterDisplayDelay)
void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,Renderable*boxImg,vf2d maxSize,Audio*dialogSound,std::vector<Memory>resourceCost,float letterDisplayDelay)
{
if(GetCurrentString()!=text){ //Make sure this is actually a new textbox
SetDefaults();
@ -13,6 +13,15 @@ void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,vf2d m
this->maxSize=maxSize;
this->resourceCost=resourceCost;
this->letterDisplayDelay=letterDisplayDelay;
this->boxImg=boxImg;
if(this->dialogSound!=nullptr){
this->dialogSound->Stop(soundHandle);
this->dialogSound=nullptr;
}
if(dialogSound!=nullptr){
this->dialogSound=dialogSound;
soundHandle=this->dialogSound->PlayCentered(1,audioVolume,true);
}
visible=true;
}
}
@ -28,17 +37,31 @@ void Textbox::SetDefaults(){
displayHeaderText="";
text="";
headerText="";
audioVolume=0;
continueWordTimer=0;
bPressed=false;
}
void Textbox::Update(PixelGameEngine*pge){
if(!visible)return;
if(!visible){
if(dialogSound!=nullptr){
audioVolume=std::max(0.f,audioVolume-pge->GetElapsedTime()*2);
dialogSound->SetVolume(soundHandle,audioVolume);
}
return;
}
lastLetterTime-=pge->GetElapsedTime();
continueWordTimer+=pge->GetElapsedTime();
if(lastLetterTime<=0){
if(textboxMarker<int(text.length()-1)){
std::string tempText=displayText;
tempText+=text[textboxMarker+1];
auto WrapText=[&](std::string&tempText,std::string&text,std::string&displayText,int&lastWordMarker,std::string&lastWord){
vf2d maxSize=this->maxSize;
if(boxImg!=nullptr){
maxSize-={26,0};
}
if(pge->GetTextSizeProp(tempText).x>=maxSize.x){
displayText=displayText.substr(0,lastWordMarker);
displayText+='\n';
@ -61,38 +84,71 @@ void Textbox::Update(PixelGameEngine*pge){
WrapText(tempHeaderText,headerText,displayHeaderText,lastHeaderWordMarker,lastHeaderWord);
}
textboxMarker++;
if(dialogSound!=nullptr){
audioVolume=std::min(1.f,audioVolume+0.01f*2);
dialogSound->SetVolume(soundHandle,audioVolume);
audioFadeOutDelay=2;
}
}else{
if(dialogSound!=nullptr){
audioFadeOutDelay=std::max(0.f,audioFadeOutDelay-0.01f);
if(audioFadeOutDelay<=0){
audioVolume=std::max(0.f,audioVolume-0.01f*2);
dialogSound->SetVolume(soundHandle,audioVolume);
}
}
}
maxSize.y=std::max(maxSize.y,float(pge->GetTextSizeProp(displayHeaderText).y+pge->GetTextSizeProp(displayText).y));
lastLetterTime=letterDisplayDelay;
}
if(textboxMarker>=int(text.length()-1)){
bPressed=pge->GetMouse(0).bPressed||pge->GetMouse(1).bPressed;
}
}
void Textbox::Draw(PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit){
void Textbox::Draw(PixelGameEngine*pge,Resources&resources,std::vector<std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit){
if(visible){
geom2d::rect<float>boxRect={pos-vf2d{3,3},maxSize+vf2d{6,6}};
geom2d::rect<float>boundingRect={pos-vf2d{3,3},maxSize+vf2d{6,6}};
if(resourceCost.size()>0){
boxRect.size.x+=36;
boxRect.size.y=std::max(36.f,boxRect.size.y);
boundingRect.size.x+=36;
boundingRect.size.y=std::max(36.f,boundingRect.size.y);
}
if(boxImg!=nullptr){
boundingRect.size.x+=26;
}
if(boundingRect.bottom().start.y>=pge->ScreenHeight()){
boundingRect.pos-={0,boundingRect.bottom().start.y-pge->ScreenHeight()};
}
if(boundingRect.right().start.x>=pge->ScreenWidth()){
boundingRect.pos-={boundingRect.right().start.x-pge->ScreenWidth(),0};
}
if(boundingRect.top().start.y<0){
boundingRect.pos+={0,-boundingRect.top().start.y};
}
if(boxRect.bottom().start.y>=pge->ScreenHeight()){
boxRect.pos-={0,boxRect.bottom().start.y-pge->ScreenHeight()};
if(boundingRect.left().start.x<0){
boundingRect.pos+={-boundingRect.left().start.x,0};
}
if(boxRect.right().start.x>=pge->ScreenWidth()){
boxRect.pos-={boxRect.right().start.x-pge->ScreenWidth(),0};
geom2d::rect<float>textboxRect=boundingRect;
if(boxImg!=nullptr){
textboxRect.pos.x+=26;
textboxRect.size.x-=50;
}
if(boxRect.top().start.y<0){
boxRect.pos+={0,-boxRect.top().start.y};
pge->FillRectDecal(boundingRect.pos,maxSize+vf2d{6,6},backCol);
pge->DrawRectDecal(boundingRect.pos+vf2d{1,1},maxSize+vf2d{4,4},WHITE);
if(boxImg!=nullptr){
pge->DrawDecal(boundingRect.pos+vf2d{3,3},IMAGES[MATRIX]->Decal(),{0.375,0.375},DARK_GREY);
pge->DrawDecal(boundingRect.pos+vf2d{3,3},boxImg->Decal());
pge->DrawRectDecal(boundingRect.pos+vf2d{3,3},{24,24},YELLOW);
}
if(boxRect.left().start.x<0){
boxRect.pos+={-boxRect.left().start.x,0};
pge->DrawShadowStringPropDecal(textboxRect.pos+vf2d{3,3},displayHeaderText,{245, 218, 66});
pge->DrawShadowStringPropDecal(textboxRect.pos+vf2d{3.f,float(3+pge->GetTextSizeProp(displayHeaderText).y)},displayText,{220,220,220});
if(textboxMarker==int(text.length()-1)&&boxImg!=nullptr){
std::string continueText="Click to Continue";
pge->DrawShadowStringPropDecal(textboxRect.pos+textboxRect.size-vf2d(pge->GetTextSizeProp(continueText))*vf2d{0.6,1}-vf2d{5,-9},continueText,{255,255,255,uint8_t(abs(sin(2*continueWordTimer))*255)},{0,0,0,uint8_t(abs(sin(2*continueWordTimer))*255)},{0.6,1});
}
pge->FillRectDecal(boxRect.pos,maxSize+vf2d{6,6},backCol);
pge->DrawRectDecal(boxRect.pos+vf2d{1,1},maxSize+vf2d{4,4},WHITE);
pge->DrawShadowStringPropDecal(boxRect.pos+vf2d{3,3},displayHeaderText,{245, 218, 66});
pge->DrawShadowStringPropDecal(boxRect.pos+vf2d{3.f,float(3+pge->GetTextSizeProp(displayHeaderText).y)},displayText,{220,220,220});
if(resourceCost.size()>0){
geom2d::rect<float>resourceBoxRect={boxRect.pos+vf2d{6+maxSize.x,0},{36,42}};
geom2d::rect<float>resourceBoxRect={textboxRect.pos+vf2d{6+maxSize.x,0},{36,42}};
pge->FillRectDecal(resourceBoxRect.pos,resourceBoxRect.size,backCol);
pge->DrawRectDecal(resourceBoxRect.pos+vf2d{1,1},resourceBoxRect.size-vf2d{2,2},WHITE);
vf2d contentPos=resourceBoxRect.pos+vf2d{3,3};
@ -143,7 +199,7 @@ void Textbox::Draw(PixelGameEngine*pge,Resources&resources,std::map<Image,std::u
totalCost+=util::GetProcedureCost(resourceCost);
index++;
}
std::string text="Size: "+std::to_string(totalCost)+" bytes";
std::string text="Size: "+std::to_string(totalCost)+" bits";
vi2d size=pge->GetTextSizeProp(text);
drawcol=WHITE;
if(totalCost+totalUsedMemory>memoryLimit){
@ -171,7 +227,7 @@ void Textbox::SetVisible(bool visible){
}
}
void Textbox::UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit){
void Textbox::UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources,std::vector<std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit){
UpdatePosition(pos);
Update(pge);
Draw(pge,resources,IMAGES,totalUsedMemory,memoryLimit);

@ -2,19 +2,26 @@
#include "olcPixelGameEngine.h"
#include "olcPGEX_TransformedView.h"
#include "Resources.h"
#include "Unit.h"
#include "olcPGEX_AudioSource.h"
#include "Memory.h"
class Textbox{
std::string headerText=""; //If a textbox has a header, it displays at the top in a special color.
std::string displayHeaderText="";
std::string text="";
std::string displayText="";
Renderable*boxImg=nullptr;
Audio*dialogSound=nullptr;
int soundHandle=-1;
float audioFadeOutDelay=2;
vf2d pos={};
vf2d maxSize={};
float audioVolume=0;
float lastLetterTime=0;
float letterDisplayDelay=0.01;
int textboxMarker=-1;
int lastWordMarker=-1;
float continueWordTimer=0;
std::string lastWord="";
int lastHeaderWordMarker=-1;
std::string lastHeaderWord="";
@ -23,17 +30,18 @@ class Textbox{
Pixel backCol=CONSTANT::MESSAGE_BOX_DEFAULT_BACKCOL;
public:
Textbox();
void Initialize(std::string text,vf2d pos={},std::string headerText="",vf2d maxSize={120,1},std::vector<Memory>resourceCost={},float letterDisplayDelay=0.01);
void Initialize(std::string text,vf2d pos={},std::string headerText="",Renderable*boxImg=nullptr,vf2d maxSize={120,1},Audio*dialogSound=nullptr,std::vector<Memory>resourceCost={},float letterDisplayDelay=0.01);
void UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit);
void UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources,std::vector<std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit);
std::string&GetCurrentString();
void SetVisible(bool visible);
vf2d GetSize();
void SetBackgroundColor(Pixel col);
bool IsVisible();
bool bPressed=false;
private:
void Update(PixelGameEngine*pge);
void UpdatePosition(vf2d newPos);
void Draw(PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit);
void Draw(PixelGameEngine*pge,Resources&resources,std::vector<std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit);
void SetDefaults();
};

@ -6,33 +6,45 @@
#include "olcPGEX_QuickGUI.h"
#include "Textbox.h"
Unit::~Unit(){};
void Unit::RandomHit(std::vector<std::unique_ptr<Audio>>&SOUNDS){
switch(rand()%3){
case 0:{SOUNDS[Sound::HIT1]->Play(GetPos(),1,0.6);}break;
case 1:{SOUNDS[Sound::HIT2]->Play(GetPos(),1,0.6);}break;
case 2:{SOUNDS[Sound::HIT3]->Play(GetPos(),1,0.6);}break;
}
}
std::string LeftShifter::unitName="Left Shifter";
std::string LeftShifter::unitDescription="Shifts target memory 1 bit to the left.";
std::vector<Memory> LeftShifter::resourceCost={{RANGE,2},{ATKSPD,2},{MOVESPD,6},{PROCEDURE,1},{HEALTH,4}};
LeftShifter::LeftShifter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
LeftShifter::LeftShifter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){}
void LeftShifter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void LeftShifter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
victim<<=1;
RandomHit(SOUNDS);
}
std::string RightShifter::unitName="Right Shifter";
std::string RightShifter::unitDescription="Shifts target memory 1 bit to the right.";
std::vector<Memory> RightShifter::resourceCost={{HEALTH,4},{RANGE,2},{ATKSPD,2},{MOVESPD,6},{PROCEDURE,1}};
RightShifter::RightShifter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
RightShifter::RightShifter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){}
void RightShifter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void RightShifter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
victim>>=1;
RandomHit(SOUNDS);
}
std::string BitRestorer::unitName="Bit Restorer";
std::string BitRestorer::unitDescription="Randomly restores 1 missing bit to a target.";
std::vector<Memory> BitRestorer::resourceCost={{PROCEDURE,6},{RANGE,1},{ATKSPD,1},{MOVESPD,2},{HEALTH,2}};
BitRestorer::BitRestorer(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
BitRestorer::BitRestorer(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){}
void BitRestorer::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void BitRestorer::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
std::vector<int>emptyMemoryPositions;
for(int i=0;i<victim.GetMemorySize();i++){
if(!victim.memory[i]){
@ -42,14 +54,15 @@ void BitRestorer::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUni
if(emptyMemoryPositions.size()==0){
//First see if we can find another damaged target, if we can, then we try healing them. Otherwise we exit.
appliedTarget.reset();
AttemptToHealOtherAllies(otherUnits);
AttemptToHealOtherAllies(otherUnits,SOUNDS);
return;
}
int randomBit=emptyMemoryPositions[rand()%emptyMemoryPositions.size()];
victim.memory[randomBit]=true;
SOUNDS[Sound::HEAL]->Play(GetPos(),1,0.6);
}
void BitRestorer::AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&otherUnits){
void BitRestorer::AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS){
std::vector<int>emptyMemoryPositions;
for(auto&u:otherUnits){
if(u.get()!=this&&u->IsFriendly()&&InRange(u)){
@ -62,6 +75,7 @@ void BitRestorer::AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&ot
int randomBit=emptyMemoryPositions[rand()%emptyMemoryPositions.size()];
u->memory[randomBit]=true;
appliedTarget=u;
SOUNDS[Sound::HEAL]->Play(GetPos(),1,0.6);
return;
}
}
@ -71,12 +85,12 @@ void BitRestorer::AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&ot
std::string MemorySwapper::unitName="Memory Swapper";
std::string MemorySwapper::unitDescription="Flips the orientation of all bits of a target around.";
std::vector<Memory> MemorySwapper::resourceCost={{RANGE,3},{ATKSPD,1},{HEALTH,3},{PROCEDURE,3},{MOVESPD,4}};
MemorySwapper::MemorySwapper(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
MemorySwapper::MemorySwapper(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,MemorySwapper::resourceCost,pos,12,*IMAGES[MEMORY_SWAPPER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable,true){
autoAcquireFriendlyTarget=false;
}
void MemorySwapper::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void MemorySwapper::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
std::vector<bool>oldMemory=victim.memory;
for(int i=0;i<oldMemory.size();i++){
victim.memory[i]=oldMemory[oldMemory.size()-i-1];
@ -110,33 +124,37 @@ void MemorySwapper::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherU
if(victim.atkSpd.index==9999999)victim.atkSpd.index=0;
if(victim.moveSpd.index==9999999)victim.moveSpd.index=0;
if(victim.procedure.index==9999999)victim.procedure.index=0;
RandomHit(SOUNDS);
}
std::string Corrupter::unitName="Corrupter";
std::string Corrupter::unitDescription="Chooses a random bit and negates it on a target.";
std::vector<Memory> Corrupter::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,8},{HEALTH,4}};
Corrupter::Corrupter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
Corrupter::Corrupter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,Corrupter::resourceCost,pos,12,*IMAGES[CORRUPTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){}
void Corrupter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void Corrupter::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
//Chooses a bit at random and corrupts it.
int randomBit=rand()%victim.memory.size();
if(victim.memory[randomBit]){
RandomHit(SOUNDS);
}
victim.memory[randomBit]=false;
}
std::string MemoryAllocator::unitName="Memory Allocator";
std::string MemoryAllocator::unitDescription="A unit that builds other units.";
std::vector<Memory> MemoryAllocator::resourceCost={{RANGE,1},{ATKSPD,1},{MOVESPD,2},{PROCEDURE,1},{HEALTH,1}};
MemoryAllocator::MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
MemoryAllocator::MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,MemoryAllocator::resourceCost,pos,12,*IMAGES[UNIT_ALLOCATOR],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,true,false){
isAllocator=true;
}
void MemoryAllocator::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void MemoryAllocator::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
}
void MemoryAllocator::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits){
void MemoryAllocator::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
if(IsBuilding()){
SetTargetLocation(CONSTANT::UNSELECTED);
target.reset();
@ -145,13 +163,14 @@ void MemoryAllocator::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<
for(int i=0;i<GetMemorySize();i++){
memory[i]=false; //Kill the unit.
}
SOUNDS[Sound::SPAWN]->Play(GetPos());
queuedUnits.push_back(std::move(buildTransformUnit));
}
}
}
void MemoryAllocator::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
if(IsBuilding()){
void MemoryAllocator::Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(IsBuilding()&&!InFogOfWar()){
game.GetPGE()->SetDrawTarget(img.Sprite());
game.GetPGE()->Clear(BLANK);
Renderable&targetImg=buildTransformUnit->GetImage();
@ -166,13 +185,16 @@ void MemoryAllocator::Draw(TileTransformedView&game,std::map<Image,std::unique_p
if(IsSelected()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE);
}
if(IsAttached()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),IsFriendly()?GREEN:RED);
}
}
}
std::string RAMBank::unitName="RAM Bank";
std::string RAMBank::unitDescription="Allows for the construction of Memory Allocators.";
std::vector<Memory> RAMBank::resourceCost={{PROCEDURE,25},{HEALTH,16}};
RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly)
RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly)
:Unit(pge,RAMBank::resourceCost,pos,41,*IMAGES[RAM_BANK],WHITE,WHITE,friendly,false
,false,false
),randomOffset({util::random(128),util::random(128)}),matrixImg(*IMAGES[MATRIX]),
@ -189,13 +211,15 @@ RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Ren
allocatorManager.colBorder = olc::YELLOW;
allocatorManager.colText = olc::WHITE;
allocatorButton = new QuickGUI::ImageButton(allocatorManager,*IMAGES[UNIT_ALLOCATOR],{0.5f,0.5f},pos-vf2d{8,48},{20,20});
isRAMBank=true;
platformStructure=true;
}
void RAMBank::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void RAMBank::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
}
void RAMBank::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits){
void RAMBank::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
pge->SetDrawTarget(img.Sprite());
for(int y=0;y<img.Sprite()->height;y++){
for(int x=0;x<img.Sprite()->width;x++){
@ -207,27 +231,30 @@ void RAMBank::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&
}
if(!soundStarted){
soundStarted=true;
soundHandle=SOUNDS[Sound::HUM]->Play(GetPos(),0.4,0.4,true);
soundHandle=SOUNDS[int(Sound::HUM)]->Play(GetPos(),0.4,0.4,true);
}
img.Decal()->Update();
pge->SetDrawTarget(nullptr);
}
void RAMBank::DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void RAMBank::DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(IsSelected()){
allocatorManager.DrawDecal(game);
}
}
void RAMBank::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void RAMBank::Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},GetUnitColor());
if(IsSelected()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE);
}
if(IsAttached()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),IsFriendly()?GREEN:RED);
}
}
void RAMBank::OnDeath(std::map<Sound,std::unique_ptr<Audio>>&SOUNDS){
SOUNDS[Sound::HUM]->Stop(soundHandle);
void RAMBank::OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){
SOUNDS[int(Sound::HUM)]->Stop(soundHandle);
}
void RAMBank::UpdateGUIState(TileTransformedView&game,Resources&player_resources,Textbox&displayBox,bool&hovered,int totalUsedMemory,int availableMemory){
@ -248,7 +275,7 @@ void RAMBank::UpdateGUIState(TileTransformedView&game,Resources&player_resources
allocatorButton->Enable(buttonEnabled);
}
bool RAMBank::ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
bool RAMBank::ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(allocatorButton->bPressed){
//First try to take one of each.
if(player_resources.atkSpd>0&&player_resources.health>0&&player_resources.moveSpd>0&&player_resources.procedure>0&&player_resources.range>0){
@ -285,14 +312,15 @@ bool RAMBank::ClickHandled(TileTransformedView&game,Resources&player_resources,s
std::string _Platform::unitName="Platform";
std::string _Platform::unitDescription="Anchored to the ground, this unit is an intermediate step for larger units.";
std::vector<Memory> _Platform::resourceCost={{HEALTH,6}};
_Platform::_Platform(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
_Platform::_Platform(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,_Platform::resourceCost,pos,24,*IMAGES[PLATFORM],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false){
isPlatform=true;
platformStructure=true;
}
void _Platform::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){};
void _Platform::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){};
void _Platform::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits){
void _Platform::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
if(IsBuilding()){
SetTargetLocation(CONSTANT::UNSELECTED);
target.reset();
@ -301,12 +329,13 @@ void _Platform::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>
for(int i=0;i<GetMemorySize();i++){
memory[i]=false; //Kill the unit.
}
SOUNDS[Sound::SPAWN]->Play(GetPos());
queuedUnits.push_back(std::move(buildTransformUnit));
}
}
}
void _Platform::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void _Platform::Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(IsBuilding()){
game.GetPGE()->SetDrawTarget(img.Sprite());
game.GetPGE()->Clear(BLANK);
@ -322,17 +351,22 @@ void _Platform::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Ren
if(IsSelected()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE);
}
if(IsAttached()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),IsFriendly()?GREEN:RED);
}
}
}
std::string Refresher::unitName="Refresher";
std::string Refresher::unitDescription="Repairs missing bits to surrounding units.";
std::vector<Memory> Refresher::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{HEALTH,4}};
Refresher::Refresher(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
Refresher::Refresher(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,Refresher::resourceCost,pos,24,*IMAGES[REFRESHER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false
,true,false){}
,true,false){
platformStructure=true;
}
void Refresher::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void Refresher::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
target.reset(); //Doesn't acquire a target.
for(auto&u:otherUnits){
if(IsFriendly()==u->IsFriendly()&&InRange(u.get())){
@ -349,14 +383,25 @@ void Refresher::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits
}
}
}
void Refresher::OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){
SOUNDS[Sound::REFRESHER]->Stop(soundHandle);
};
void Refresher::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
if(!soundStarted){
soundStarted=true;
soundHandle=SOUNDS[Sound::REFRESHER]->Play(GetPos(),1,1,true);
}
};
std::string Turret::unitName="Turret";
std::string Turret::unitDescription="Automatically targets attack and movement speed memory ranges before others.";
std::vector<Memory> Turret::resourceCost={{ATKSPD,4},{RANGE,5},{HEALTH,6},{PROCEDURE,16}};
Turret::Turret(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,Turret::resourceCost,pos,24,*IMAGES[TURRET],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false){}
Turret::Turret(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,Turret::resourceCost,pos,24,*IMAGES[TURRET],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false){
platformStructure=true;
}
void Turret::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void Turret::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
if(victim.GetMoveSpd()>0){
for(int i=0;i<victim.moveSpd.size;i++){
if(victim.memory[victim.moveSpd.index+i]){
@ -384,15 +429,26 @@ void Turret::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
attempts++;
}
}
void Turret::OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){
SOUNDS[Sound::TURRET]->Stop(soundHandle);
};
void Turret::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
if(!soundStarted){
soundStarted=true;
soundHandle=SOUNDS[Sound::TURRET]->Play(GetPos(),1,1,true);
}
};
std::string MemoryGuard::unitName="Memory Guard";
std::string MemoryGuard::unitDescription="Reduces the chance of bit modification for all surrounding units by 30%";
std::vector<Memory> MemoryGuard::resourceCost={{HEALTH,10},{ATKSPD,4},{RANGE,4},{PROCEDURE,12}};
MemoryGuard::MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
MemoryGuard::MemoryGuard(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly,bool moveable)
:Unit(pge,MemoryGuard::resourceCost,pos,24,*IMAGES[MEMORY_GUARD],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false
,true,false){}
,true,false){
platformStructure=true;
}
void MemoryGuard::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits){
void MemoryGuard::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits ,std::vector<std::unique_ptr<Audio>>&SOUNDS){
target.reset(); //Doesn't acquire a target.
for(auto&u:otherUnits){
if(IsFriendly()==u->IsFriendly()&&InRange(u.get())){
@ -400,6 +456,15 @@ void MemoryGuard::Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUni
}
}
}
void MemoryGuard::OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){
SOUNDS[Sound::MEMORY_GUARD]->Stop(soundHandle);
};
void MemoryGuard::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){
if(!soundStarted){
soundStarted=true;
soundHandle=SOUNDS[Sound::MEMORY_GUARD]->Play(GetPos(),1,1,true);
}
};
Unit::Unit(PixelGameEngine*pge,std::vector<Memory>memory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable)
:pos(pos),radius(radius),ghostPos({-999999,-999999}),img(img),targetLineCol(targetLineColor),attackingLineCol(attackingLineColor),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){
@ -438,7 +503,7 @@ Unit::Unit(PixelGameEngine*pge,std::vector<Memory>memory,vf2d pos,float radius,R
targetingLine.Create(25,24,false,false);
}
void Unit::DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(!CanInteractWithAllies()&&!CanInteractWithEnemies())return;
float dist=geom2d::line<float>(game.ScreenToWorld(pge->GetMousePos()),GetGhostPos()).length();
float range=12*(GetRange()+1);
@ -474,16 +539,19 @@ void Unit::DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::
}
}
void Unit::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},GetUnitColor());
if(IsSelected()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE);
}
if(IsAttached()){
game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),IsFriendly()?GREEN:RED);
}
}
void Unit::DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){}
void Unit::DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){}
void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::_DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool unitMetersGreyedOut){
DrawHud(game,IMAGES);
int initialBarX=ghostPos.x-GetMemorySize()/2*CONSTANT::BAR_SQUARE_SIZE.x-CONSTANT::BAR_SQUARE_SIZE.x/2;
int initialBarY=ghostPos.y-CONSTANT::BAR_SQUARE_SIZE.y-img.Sprite()->height/2-2;
@ -495,16 +563,16 @@ void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Rend
col=CONSTANT::HEALTH_COLOR;
}
if(range.index==i&&range.size>0){
col=CONSTANT::RANGE_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::RANGE_COLOR;
}
if(atkSpd.index==i&&atkSpd.size>0){
col=CONSTANT::ATKSPD_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::ATKSPD_COLOR;
}
if(moveSpd.index==i&&moveSpd.size>0){
col=CONSTANT::MOVESPD_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::MOVESPD_COLOR;
}
if(procedure.index==i&&procedure.size>0){
col=CONSTANT::PROCEDURE_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::PROCEDURE_COLOR;
}
};
@ -514,19 +582,19 @@ void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Rend
}
if(GetAtkSpd()>0){
game.FillRectDecal(vf2d{float(initialBarX)+atkSpd.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*atkSpd.size-1,2},CONSTANT::ATKSPD_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*atkSpd.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::ATKSPD_COLOR);
}
if(GetMoveSpd()>0){
game.FillRectDecal(vf2d{float(initialBarX)+moveSpd.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*moveSpd.size-1,2},CONSTANT::MOVESPD_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*moveSpd.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::MOVESPD_COLOR);
}
if(GetProcedure()>0){
game.FillRectDecal(vf2d{float(initialBarX)+procedure.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*procedure.size-1,2},CONSTANT::PROCEDURE_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*procedure.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::PROCEDURE_COLOR);
}
if(GetRange()>0){
game.FillRectDecal(vf2d{float(initialBarX)+range.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*range.size-1,2},CONSTANT::RANGE_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*range.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::RANGE_COLOR);
}
for(int i=0;i<GetMemorySize();i++){
@ -539,29 +607,31 @@ void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Rend
}
}
void Unit::DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
if(!target.expired()){
geom2d::line<float>lineToTarget(pos,target.lock()->pos);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,1},targetLineCol);
} else
if(targetLoc!=CONSTANT::UNSELECTED){
geom2d::line<float>lineToTarget(pos,targetLoc);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,0.6},CONSTANT::MOVE_LINE_COL);
}
if(!appliedTarget.expired()){
geom2d::line<float>lineToTarget(pos,appliedTarget.lock()->pos);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
if(reloadTimer>0){
util::ApplyMatrixEffect(game.GetPGE(),attackingLine,*IMAGES[ATTACKING_LINE],IMAGES[MATRIX]);
float reloadSpd=1.f/(GetAtkSpd()/2.f);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),attackingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*30,0},{lineToTarget.length(),24},{1,1+(attackFailed?-0.3f:(reloadTimer/reloadSpd)*0.25f)},attackFailed?Pixel{192,192,192,130}:Pixel{attackingLineCol.r,attackingLineCol.g,attackingLineCol.b,uint8_t(IsFriendly()?200:160)});
void Unit::DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES){
if(!InFogOfWar()){
if(!target.expired()){
geom2d::line<float>lineToTarget(pos,target.lock()->pos);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,1},targetLineCol);
} else
if(targetLoc!=CONSTANT::UNSELECTED){
geom2d::line<float>lineToTarget(pos,targetLoc);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,0.6},CONSTANT::MOVE_LINE_COL);
}
if(!appliedTarget.expired()){
geom2d::line<float>lineToTarget(pos,appliedTarget.lock()->pos);
lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2);
lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4);
if(reloadTimer>0){
util::ApplyMatrixEffect(game.GetPGE(),attackingLine,*IMAGES[ATTACKING_LINE],IMAGES[MATRIX]);
float reloadSpd=1.f/(GetAtkSpd()/2.f);
game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),attackingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*30,0},{lineToTarget.length(),24},{1,1+(attackFailed?-0.3f:(reloadTimer/reloadSpd)*0.25f)},attackFailed?Pixel{192,192,192,130}:Pixel{attackingLineCol.r,attackingLineCol.g,attackingLineCol.b,uint8_t(IsFriendly()?200:160)});
}
}
}
float dist=geom2d::line<float>(game.ScreenToWorld(pge->GetMousePos()),GetGhostPos()).length();
@ -607,7 +677,21 @@ int Unit::GetBits(Marker&m){
return activeBits;
}
void Unit::OnDeath(std::map<Sound,std::unique_ptr<Audio>>&SOUNDS){}
void Unit::_OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){
switch(rand()%3){
case 0:{
SOUNDS[Sound::DEAD1]->Play(GetPos());
}break;
case 1:{
SOUNDS[Sound::DEAD2]->Play(GetPos());
}break;
case 2:{
SOUNDS[Sound::DEAD3]->Play(GetPos());
}break;
}
OnDeath(SOUNDS);
}
void Unit::OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS){}
int Unit::GetHealth(){
return GetBits(health);
@ -639,7 +723,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,std::vector<ResourceGainIcon>&resourceGainIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::_Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer,std::vector<ResourceGainIcon>&resourceGainIcons,std::vector<std::unique_ptr<Renderable>>&IMAGES,GameFlags&flags){
if(!target.expired()){
auto ptrTarget=target.lock();
if(!InRange(ptrTarget)&&CanMove()){
@ -663,28 +747,76 @@ void Unit::_Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SO
}
if(!attachedPoint.expired()){
SetPos(attachedPoint.lock()->pos+vf2d{cos(float(attachedPoint.lock()->rot+PI/2))*16,sin(float(attachedPoint.lock()->rot+PI/2))*16});
collectionTime-=pge->GetElapsedTime();
if(collectionTime<=0){
collectionTime=CONSTANT::COLLECTION_WAIT_TIME;
Resources&targetResource=IsFriendly()?player_resources:enemy_resources;
switch(attachedPoint.lock()->type){
case HEALTH:{
if(!IsFriendly()&&flags.difficulty==2){
targetResource.health+=3;
}
if(!IsFriendly()&&flags.difficulty==1){
targetResource.health++;
}
if(!IsFriendly()&&flags.difficulty==0){
targetResource.health--;
}
targetResource.health++;
}break;
case RANGE:{
if(!IsFriendly()&&flags.difficulty==2){
targetResource.range+=3;
}
if(!IsFriendly()&&flags.difficulty==1){
targetResource.range++;
}
if(!IsFriendly()&&flags.difficulty==0){
targetResource.range--;
}
targetResource.range++;
}break;
case ATKSPD:{
if(!IsFriendly()&&flags.difficulty==2){
targetResource.atkSpd+=3;
}
if(!IsFriendly()&&flags.difficulty==1){
targetResource.atkSpd++;
}
if(!IsFriendly()&&flags.difficulty==0){
targetResource.atkSpd--;
}
targetResource.atkSpd++;
}break;
case MOVESPD:{
if(!IsFriendly()&&flags.difficulty==2){
targetResource.moveSpd+=3;
}
if(!IsFriendly()&&flags.difficulty==1){
targetResource.moveSpd++;
}
if(!IsFriendly()&&flags.difficulty==0){
targetResource.moveSpd--;
}
targetResource.moveSpd++;
}break;
case PROCEDURE:{
if(!IsFriendly()&&flags.difficulty==2){
targetResource.procedure+=3;
}
if(!IsFriendly()&&flags.difficulty==1){
targetResource.procedure++;
}
if(!IsFriendly()&&flags.difficulty==0){
targetResource.procedure--;
}
targetResource.procedure++;
}break;
}
resourceGainIcons.push_back({IMAGES[RESOURCE].get(),attachedPoint.lock()->type,GetPos()});
if(!InFogOfWar()){
resourceGainIcons.push_back({IMAGES[RESOURCE].get(),attachedPoint.lock()->type,GetPos()});
}
}
}
@ -788,7 +920,7 @@ void Unit::SetPos(vf2d newPos){
pos=newPos;
}
void Unit::AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<DebuffIcon>&debuffIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<DebuffIcon>&debuffIcons,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS){
if(reloadTimer>0)return;
std::weak_ptr<Unit>finalTarget;
if(!unit.expired()){
@ -807,7 +939,7 @@ void Unit::AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std
bool hadMoveSpd=finalTarget.lock()->GetMoveSpd()>0;
bool hadRange=finalTarget.lock()->GetRange()>0;
bool hadProcedure=finalTarget.lock()->GetProcedure()>0;
_Attack(attacker,finalTarget,otherUnits); //Call the parent function first, followed by the child.
_Attack(attacker,finalTarget,otherUnits,SOUNDS); //Call the parent function first, followed by the child.
if(hadAtkSpd&&finalTarget.lock()->GetAtkSpd()==0){
debuffIcons.emplace_back(IMAGES[RLD_ICON].get(),IMAGES[RED_X].get(),finalTarget.lock()->GetPos()-vf2d{util::random(12)-6,4});
}
@ -824,24 +956,42 @@ void Unit::AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std
}
}
void Unit::Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits){}
void Unit::Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits){}
void Unit::Attacked(std::weak_ptr<Unit>attacker){}
void Unit::_Attacked(std::weak_ptr<Unit>attacker){
void Unit::_Attacked(std::weak_ptr<Unit>attacker,std::vector<std::shared_ptr<Unit>>&otherUnits){
Attacked(attacker);
if(attacker.lock()->IsFriendly()!=IsFriendly()&&CanInteractWithEnemies()){
SetTargetUnit(attacker);
}
if(!IsFriendly()&&!attacker.lock()->IsFriendly()&&!attacker.lock()->CanInteractWithAllies()){
attacker.lock()->SetTargetLocation(attacker.lock()->GetPos()); //This effectively negates enemies targeting each other for attacking if they're not supposed to. Somehow this occurs sometimes.
}
if(!IsFriendly()&&attacker.lock()->IsFriendly()!=IsFriendly()){
for(auto&u:otherUnits){
if(this!=u.get()&&!u->IsFriendly()&&u->GetCurrentTarget().expired()&&u->CanMove()&&!u->IsAllocator()){
geom2d::line<float>distLine={GetPos(),u->GetPos()};
if(distLine.length()<320){
if(u->CanInteractWithEnemies()){
u->SetTargetUnit(attacker);
}else
if(u->CanInteractWithAllies()){
u->SetTargetLocation(GetPos());
}
}
}
}
}
}
void Unit::_Attack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>finalTarget,std::vector<std::shared_ptr<Unit>>&otherUnits){
void Unit::_Attack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>finalTarget,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS){
if(GetProcedure()>0&&GetAtkSpd()>0){
attackFailed=false;
float procChance=float(GetProcedure())/procedure.size;
if(util::random(1)>=1-procChance){
Attack(*finalTarget.lock(),otherUnits);
finalTarget.lock()->_Attacked(attacker);
Attack(*finalTarget.lock(),otherUnits,SOUNDS);
finalTarget.lock()->_Attacked(attacker,otherUnits);
reloadTimer=1.f/(GetAtkSpd()/2.f);
if(GetCurrentTarget().expired()&&!IsFriendly()){
if(finalTarget.lock()->IsFriendly()!=IsFriendly()&&CanInteractWithEnemies()){
@ -931,7 +1081,7 @@ Pixel Unit::GetUnitColor(){
}
}
bool Unit::ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
bool Unit::ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES){
return false;
};
@ -941,7 +1091,14 @@ bool Unit::IsAllocator(){
return isAllocator&&attachedPoint.expired()&&buildTime<=0;
}
void Unit::SetBuildUnit(float buildTime,std::unique_ptr<Unit>finalUnit){
void Unit::SetBuildUnit(float buildTime,std::shared_ptr<Unit>finalUnit,std::vector<std::unique_ptr<Audio>>&SOUNDS){
if(this->IsAllocator()){
SOUNDS[Sound::SMALLBUILD]->Play(GetPos());
} else
if(this->IsPlatform()){
SOUNDS[Sound::BIGBUILD]->Play(GetPos());
}
//Once the units start building they aren't considered allocators/platforms anymore, must do it before.
this->buildTime=buildTime;
this->buildTransformUnit=std::move(finalUnit);
}
@ -973,3 +1130,11 @@ bool Unit::IsAttached(){
Unit*Unit::GetBuildUnit(){
return buildTransformUnit.get();
}
bool Unit::IsRAMBank(){
return isRAMBank;
}
bool Unit::IsPlatformStructure(){
return platformStructure;
}

@ -8,12 +8,12 @@
#include "olcPGEX_AudioSource.h"
#include "DebuffIcon.h"
#include "CollectionPoint.h"
#include "MemoryType.h"
#include "Resources.h"
#include "Textbox.h"
#include "Memory.h"
#include "GameFlags.h"
#include "olcPGEX_QuickGUI.h"
class Textbox;
enum class UnitType{
LeftShifter,
RightShifter,
@ -33,14 +33,11 @@ struct Marker{
size_t size;
};
struct Memory{
MemoryType type;
int size;
};
struct Unit{
friend class Scenario;
public:
Unit(PixelGameEngine*pge,std::vector<Memory>memory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true);
virtual~Unit();
int GetHealth();
int GetRange();
int GetAtkSpd();
@ -50,12 +47,13 @@ public:
std::vector<bool>memory;
std::vector<bool>ghostMemory;
std::vector<bool>savedMemory;
virtual void Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits);
virtual void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)=0;
virtual void Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
virtual void DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void _DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
virtual void OnDeath(std::map<Sound,std::unique_ptr<Audio>>&SOUNDS);
virtual void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits);
virtual void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)=0;
virtual void Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES);
virtual void DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES);
void _DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool unitMetersGreyedOut);
void _OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS);
virtual void OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool IsFriendly();
bool IsSelected();
void Select();
@ -66,43 +64,47 @@ public:
void SetTargetUnit(std::weak_ptr<Unit>target);
void SetTargetLocation(vf2d targetLoc);
void SetPos(vf2d newPos);
void AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<DebuffIcon>&debuffIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void AttemptAttack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>unit,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<DebuffIcon>&debuffIcons,std::vector<std::unique_ptr<Renderable>>&IMAGES,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool InFogOfWar();
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,std::vector<ResourceGainIcon>&resourceGainIcons,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void _Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector<std::shared_ptr<Unit>>&queuedUnits,std::array<float,5>&resourceGainTimer,std::vector<ResourceGainIcon>&resourceGainIcons,std::vector<std::unique_ptr<Renderable>>&IMAGES,GameFlags&flags);
bool IsMoveable();
void DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES);
bool CanInteractWithEnemies();
bool CanInteractWithAllies();
Renderable&GetImage();
virtual void RunAI(PixelGameEngine*pge);
void _RunAI(PixelGameEngine*pge);
virtual void Attacked(std::weak_ptr<Unit>attacker);
void _Attacked(std::weak_ptr<Unit>attacker);
void _Attacked(std::weak_ptr<Unit>attacker,std::vector<std::shared_ptr<Unit>>&otherUnits);
std::weak_ptr<Unit>GetCurrentTarget();
void DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES);
bool AutoAcquiresFriendlyTargets();
bool CanMove();
void SetTargetCollectionPoint(std::weak_ptr<CollectionPoint>targetCP,std::weak_ptr<Unit>self_ptr);
Pixel GetUnitColor();
virtual void UpdateGUIState(TileTransformedView&game,Resources&player_resources,Textbox&displayBox,bool&hovered,int totalUsedMemory,int availableMemory);
virtual bool ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::map<Image,std::unique_ptr<Renderable>>&IMAGES); //If you return true here, then the left click does not pass back to the main Virus Attack class.
virtual bool ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES); //If you return true here, then the left click does not pass back to the main Virus Attack class.
bool IsAllocator();
void SetBuildUnit(float buildTime,std::unique_ptr<Unit>finalUnit);
void SetBuildUnit(float buildTime,std::shared_ptr<Unit>finalUnit,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool IsBuilding();
void SetGuardTime(float time);
bool IsGuarded();
void SaveMemory();
bool IsPlatform();
bool IsAttached();
bool IsRAMBank();
void RandomHit(std::vector<std::unique_ptr<Audio>>&SOUNDS); //3 of chance odds of making a sound.
Unit*GetBuildUnit();
Marker health={};
Marker range={};
Marker atkSpd={};
Marker moveSpd={};
Marker procedure={};
bool platformStructure=false;
bool IsPlatformStructure();
std::vector<bool>& operator <<=(const int n){
for(int i=0;i<GetMemorySize()-1;i++){
@ -133,8 +135,9 @@ protected:
bool autoAcquireFriendlyTarget=true;
bool isAllocator=false;
bool isPlatform=false;
std::unique_ptr<Unit>buildTransformUnit;
std::shared_ptr<Unit>buildTransformUnit;
float buildTime=0;
bool isRAMBank=false;
private:
Renderable targetingLine;
Renderable attackingLine;
@ -145,7 +148,7 @@ private:
int GetBits(Marker&m);
bool selected=false;
bool dead=false;
void _Attack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>finalTarget,std::vector<std::shared_ptr<Unit>>&otherUnits);
void _Attack(std::weak_ptr<Unit>attacker,std::weak_ptr<Unit>finalTarget,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
bool moveable=true;
bool friendlyInteractable=false;
bool enemyInteractable=true;
@ -161,51 +164,51 @@ private:
};
struct LeftShifter:Unit{
LeftShifter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
LeftShifter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct RightShifter:Unit{
RightShifter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
RightShifter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct BitRestorer:Unit{
BitRestorer(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
void AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&otherUnits);
BitRestorer(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void AttemptToHealOtherAllies(std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS);
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct MemorySwapper:Unit{
MemorySwapper(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
MemorySwapper(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct Corrupter:Unit{
Corrupter(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
Corrupter(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct MemoryAllocator:Unit{
MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&units)override;
void Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits)override;
void Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES)override;
MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
@ -217,51 +220,63 @@ struct RAMBank:Unit{
Renderable&originalImg;
Renderable&matrixImg;
bool soundStarted=false;
int soundHandle;
int soundHandle=-1;
QuickGUI::Manager allocatorManager;
QuickGUI::ImageButton*allocatorButton;
RAMBank(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false);
void Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits)override;
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
void Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES)override;
void OnDeath(std::map<Sound,std::unique_ptr<Audio>>&SOUNDS)override;
bool ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::map<Image,std::unique_ptr<Renderable>>&IMAGES)override;
RAMBank(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false);
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES)override;
void OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
bool ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector<std::shared_ptr<Unit>>&units,std::vector<std::unique_ptr<Renderable>>&IMAGES)override;
void UpdateGUIState(TileTransformedView&game,Resources&player_resources,Textbox&displayBox,bool&hovered,int totalUsedMemory,int availableMemory)override;
void DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES)override;
void DrawHud(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct _Platform:Unit{
_Platform(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
void Update(PixelGameEngine*pge,std::map<Sound,std::unique_ptr<Audio>>&SOUNDS,std::vector<std::unique_ptr<Unit>>&queuedUnits)override;
void Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES)override;
_Platform(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Draw(TileTransformedView&game,std::vector<std::unique_ptr<Renderable>>&IMAGES)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct MemoryGuard:Unit{
MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
bool soundStarted=false;
int soundHandle=-1;
MemoryGuard(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct Refresher:Unit{
Refresher(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
bool soundStarted=false;
int soundHandle=-1;
Refresher(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;
};
struct Turret:Unit{
Turret(PixelGameEngine*pge,vf2d pos,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)override;
bool soundStarted=false;
int soundHandle=-1;
Turret(PixelGameEngine*pge,vf2d pos,std::vector<std::unique_ptr<Renderable>>&IMAGES,bool friendly=false,bool moveable=true);
void Update(PixelGameEngine*pge,std::vector<std::unique_ptr<Audio>>&SOUNDS,std::vector<std::shared_ptr<Unit>>&queuedUnits)override;
void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits,std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
void OnDeath(std::vector<std::unique_ptr<Audio>>&SOUNDS)override;
static std::vector<Memory> resourceCost;
static std::string unitName;
static std::string unitDescription;

File diff suppressed because it is too large Load Diff

@ -5,6 +5,7 @@
#include "olcPGEX_AudioListener.h"
#include "olcPGEX_AudioSource.h"
#include "olcPGEX_SplashScreen.h"
#include "olcPGEX_QuickGUI.h"
#include "Unit.h"
#include "Constant.h"
#include "Image.h"
@ -15,8 +16,8 @@
#include "Resources.h"
#include "Textbox.h"
#include "Level.h"
class Scenario;
#include "GameFlags.h"
#include "GameState.h"
struct Letter{
vf2d pos;
@ -26,36 +27,42 @@ struct Letter{
class VirusAttack : public olc::PixelGameEngine
{
friend class Stage1;
private:
public:
#ifdef SPLASH_ENABLED
SplashScreen splash;
#endif
vi2d WORLD_SIZE={64,64};
std::vector<std::unique_ptr<Unit>>queuedUnits;
std::vector<std::shared_ptr<Unit>>queuedUnits;
std::vector<std::shared_ptr<Unit>>units;
std::vector<std::shared_ptr<CollectionPoint>>collectionPoints;
std::vector<std::unique_ptr<DeathAnimation>>deathAnimations;
std::vector<DebuffIcon>debuffIcons;
std::vector<ResourceGainIcon>resourceGainIcons;
std::vector<Scenario*>scenarios;
std::map<Image,std::unique_ptr<Renderable>>IMAGES;
std::map<Sound,std::unique_ptr<Audio>>SOUNDS;
olcPGEX_AudioListener AL;
Audio*bgm=nullptr;
int bgm_handle=-1;
Resources player_resources,player_prev_resources,player_display_resources,enemy_resources;
TileTransformedView game;
TileTransformedView gametv;
Textbox unitCreationBox,testBox,memoryAllocatorBox,platformCreationBox;
Textbox unitCreationBox,testBox,memoryAllocatorBox,platformCreationBox,restartBox;
Level*currentLevel;
float gameplayTime;
int gameSeconds;
int audioMode=0; //0=Play everything, 1=Play sound effects, 2=Everything off.
std::map<LevelName,Level>levelData;
QuickGUI::Manager mainMenu;
QuickGUI::TransparentButton*campaignStartButton;
QuickGUI::TransparentButton*audioToggleButton;
QuickGUI::TransparentButton*difficultyToggleButton;
QuickGUI::TransparentButton*exitGameButton;
QuickGUI::Manager restartManager;
QuickGUI::TransparentImageButton*restartButton;
QuickGUI::Manager unitCreationList;
QuickGUI::ImageButton*leftShifterButton;
QuickGUI::ImageButton*rightShifterButton;
@ -84,10 +91,37 @@ private:
float memoryDisplayDelay=0;
bool memoryIncreased=true;
float memoryChangeTimer=2;
float levelForegroundFade=0;
LevelName levelToLoad;
bool reloadLevel=false;
bool restartButtonHeldDown=false;
float restartButtonHoldTime=0;
GameState state=GameState::MAIN_MENU;
float nextColorChange=10;
std::array<Pixel,7>colorChangeOptions={VERY_DARK_BLUE,VERY_DARK_CYAN,VERY_DARK_GREEN,VERY_DARK_GREY,VERY_DARK_MAGENTA,VERY_DARK_RED,VERY_DARK_YELLOW};
Pixel currentBackCol;
Pixel newCol;
float transition=0;
float flickerAmt=1;
float arrowScroll=0;
Renderable attackingLineModified;
Renderable titleScreenText;
float titleScreenY=-200;
float textOrientationY=0;
float textOrientationX=0;
int currentScenario=0;
GameFlags flags;
float flashTimer=0;
Textbox completedBox;
Textbox creditsBox;
std::string objective="";
vf2d randomBackgroundOffset;
vf2d startingDragPos=CONSTANT::UNSELECTED;
void HandleGUIDisplay();
void HandleDraggingSelection();
void DrawSelectionRectangle();
void HandleRightClickMove();
@ -117,6 +151,11 @@ private:
void DrawSystemMemoryBar(float fElapsedTime);
void CalculateUsedMemory();
void InitializeScenarios();
void PerformLevelTransition(float fElapsedTime);
void RestartLevel();
void HandleRestartButton(float fElapsedTime);
void DrawCurvedTexture(vf2d offset,vf2d size,Decal*decal,vf2d texOffset,Pixel col=WHITE,float curveThickness=0.8);
std::string DisplayTime(int gameSeconds);
public:
VirusAttack();

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 827 B

After

Width:  |  Height:  |  Size: 827 B

@ -1,2 +1,2 @@
~\Documents\emsdk\emsdk_env.ps1 activate latest
em++ -std=c++20 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 -s USE_SDL_MIXER=2 -sSTACK_SIZE=5MB $(Get-ChildItem *.cpp) soloud.o -o pge.html --preload-file assets
em++ -std=c++20 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 -s USE_SDL_MIXER=2 -sSTACK_SIZE=10MB $(Get-ChildItem *.cpp) soloud.o -o pge.html --preload-file assets

@ -83,6 +83,8 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>soloud_static.lib;sdl2.lib;sdl2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<StackReserveSize>2000000</StackReserveSize>
<HeapReserveSize>2000000</HeapReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -102,6 +104,8 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>soloud_static.lib;sdl2.lib;sdl2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<StackReserveSize>2000000</StackReserveSize>
<HeapReserveSize>2000000</HeapReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -117,6 +121,8 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>soloud_static.lib;sdl2.lib;sdl2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<StackReserveSize>2000000</StackReserveSize>
<HeapReserveSize>2000000</HeapReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -136,6 +142,8 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>soloud_static.lib;sdl2.lib;sdl2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<StackReserveSize>2000000</StackReserveSize>
<HeapReserveSize>2000000</HeapReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -143,8 +151,11 @@
<ClInclude Include="Constant.h" />
<ClInclude Include="DeathAnimation.h" />
<ClInclude Include="DebuffIcon.h" />
<ClInclude Include="GameFlags.h" />
<ClInclude Include="GameState.h" />
<ClInclude Include="Image.h" />
<ClInclude Include="Level.h" />
<ClInclude Include="Memory.h" />
<ClInclude Include="MemoryType.h" />
<ClInclude Include="olcPGEX_AudioListener.h" />
<ClInclude Include="olcPGEX_AudioSource.h" />

@ -99,6 +99,15 @@
<ClInclude Include="Scenario.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GameState.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GameFlags.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="VirusAttack.cpp">

@ -68,7 +68,7 @@ class olcPGEX_AudioSource : public olc::PGEX
{
public:
// Pointer to the Audio Listener for this object
olcPGEX_AudioListener* AL;
olcPGEX_AudioListener* AL=nullptr;
// Handle for this particular copy of the sound
int handle = 255;
@ -104,7 +104,7 @@ public:
// Instruct Audio Listener to load this sound (if not loaded already)
void LoadAudioSample(int ID, const char* fileName);
void PlayCentered(float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false);
int PlayCentered(float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false,bool bgm=false);
// Play the Audio Sample, with given parameters
int Play(vf2d pos, float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false);
@ -122,6 +122,7 @@ public:
// Adjust Volume
void SetVolume(float vol, float minVol = 0.0f, float maxVol = 1.0f);
void SetVolume(int handle,float vol);
// Set Default Parameters
void SetDefaults(float speed, float vol, float minVol, float maxVol, bool looping);
@ -140,8 +141,10 @@ void olcPGEX_AudioSource::LoadAudioSample(int ID, const char* fileName)
AL->LoadAudioSample(ID, fileName);
}
void olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, bool paused)
int olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, bool paused,bool bgm)
{
if(bgm&&!AL->bMusicOn)return -1;
if(!bgm&&!AL->bSoundOn)return -1;
// Set parameters
fPlaySpeed = speed;
fVolume = vol;
@ -158,10 +161,12 @@ void olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, boo
// Update Play status
bIsPlaying = true;
return handle;
}
int olcPGEX_AudioSource::Play(vf2d pos, float speed, float vol, bool looping, bool paused)
{
if(!AL->bSoundOn||isnan(pos.x)||isnan(pos.y))return -1;
// Set parameters
fPlaySpeed = speed;
fVolume = vol*std::max(0.f,abs(1-std::min(1.0f,(AL->GetDistance(pos)/1024.f))));
@ -198,7 +203,9 @@ void olcPGEX_AudioSource::Pause(bool pauseState)
void olcPGEX_AudioSource::Stop(int handle)
{
// Use the Audio Listener to stop the sound
AL->soloud.stop(handle);
if(handle!=-1){
AL->soloud.stop(handle);
}
}
void olcPGEX_AudioSource::Stop()
@ -231,6 +238,15 @@ void olcPGEX_AudioSource::ModulateAudio(float minPlaySpeed, float maxPlaySpeed,
AL->soloud.setRelativePlaySpeed(handle, fPlaySpeed);
}
void olcPGEX_AudioSource::SetVolume(int handle,float vol)
{
// Set volume
fVolume = vol;
// Instruct the Audio Listener to apply the volume change
AL->soloud.setVolume(handle, fVolume);
}
void olcPGEX_AudioSource::SetVolume(float vol, float minVol, float maxVol)
{
// Set volume

@ -252,6 +252,31 @@ namespace olc::QuickGUI
void DrawDecal(PixelGameEngine*pge) override;
};
// Creates a Button Control - a clickable, labelled rectangle
class TransparentButton : public Button
{
public:
TransparentButton(olc::QuickGUI::Manager& manager, // Associate with a Manager
const std::string& text, // Text to display
const olc::vf2d& pos, // Location of button top-left
const olc::vf2d& size, // Location of button top-left
const Pixel& hoverCol); // Size of button
public:
// Position of button
olc::vf2d vPos;
// Size of button
olc::vf2d vSize;
// Text displayed on button
std::string sText;
Pixel hoverCol;
public: // BaseControl overrides
void Draw(TileTransformedView&pge) override;
void DrawDecal(TileTransformedView&pge) override;
void DrawDecal(PixelGameEngine*pge) override;
};
// Creates a Button Control - a clickable, labelled rectangle
class CheckBox : public Button
{
@ -290,6 +315,27 @@ namespace olc::QuickGUI
void DrawDecal(PixelGameEngine*pge) override;
};
class TransparentImageButton : public ImageButton
{
public:
TransparentImageButton(olc::QuickGUI::Manager& manager, // Associate with a Manager
const olc::Renderable &icon, // Text to display
const olc::Renderable &iconHover, // Text to display
const olc::vf2d& iconScale,
const olc::vf2d& pos, // Location of button top-left
const olc::vf2d& size); // Size of button
public:
const olc::Renderable& pIcon;
const olc::Renderable& pIconHover;
olc::vf2d iconScale;
public:
void Draw(TileTransformedView&pge) override;
void DrawDecal(TileTransformedView&pge) override;
void DrawDecal(PixelGameEngine*pge) override;
};
class ImageCheckBox : public ImageButton
{
public:
@ -750,8 +796,9 @@ namespace olc::QuickGUI
vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y;
bPressed = false;
bReleased = false;
if (m_state == State::Disabled || !bVisible)
if (m_state == State::Disabled || !bVisible) {
return;
}
float fElapsedTime = pge->GetElapsedTime();
@ -866,6 +913,40 @@ namespace olc::QuickGUI
}
#pragma endregion
#pragma region TransparentButton
TransparentButton::TransparentButton(olc::QuickGUI::Manager& manager, const std::string& text, const olc::vf2d& pos, const olc::vf2d& size,const Pixel& hoverCol)
: Button(manager,text,pos,size),hoverCol(hoverCol)
{
vPos = pos; vSize = size; sText = text;
}
void TransparentButton::Draw(TileTransformedView&pge)
{
if (!bVisible)
return;
pge.DrawRect(vPos, vSize - olc::vf2d(1, 1), m_manager.colBorder);
olc::vf2d vText = pge.GetPGE()->GetTextSize(sText);
//pge.DrawShadowString(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,{1,1},olc::PixelLerp(m_manager.colText, hoverCol, m_fTransition));
}
void TransparentButton::DrawDecal(TileTransformedView&pge)
{
if (!bVisible)
return;
olc::vf2d vText = pge.GetPGE()->GetTextSizeProp(sText);
pge.DrawShadowStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,olc::PixelLerp(BLACK, hoverCol, m_fTransition));
}
void TransparentButton::DrawDecal(PixelGameEngine*pge)
{
if (!bVisible)
return;
olc::vf2d vText = pge->GetTextSizeProp(sText);
pge->DrawShadowStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText,olc::PixelLerp(BLACK, hoverCol, m_fTransition));
}
#pragma endregion
#pragma region ImageButton
ImageButton::ImageButton(olc::QuickGUI::Manager& manager, const olc::Renderable& icon, const olc::vf2d& iconScale, const olc::vf2d& pos, const olc::vf2d& size)
@ -893,6 +974,43 @@ namespace olc::QuickGUI
};
#pragma endregion
#pragma region TransparentImageButton
TransparentImageButton::TransparentImageButton(olc::QuickGUI::Manager& manager, const olc::Renderable& icon, const olc::Renderable& iconHover, const olc::vf2d& iconScale, const olc::vf2d& pos, const olc::vf2d& size)
: ImageButton(manager, icon, iconScale, pos, size), pIcon(icon), pIconHover(iconHover), iconScale(iconScale)
{
}
void TransparentImageButton::Draw(TileTransformedView&pge)
{
if (!bVisible) return;
//Button::Draw(pge);
if(bHover){
pge.DrawSprite(vPos + olc::vi2d(4, 4), pIconHover.Sprite());
} else {
pge.DrawSprite(vPos + olc::vi2d(4, 4), pIcon.Sprite());
}
}
void TransparentImageButton::DrawDecal(TileTransformedView&pge){
if (!bVisible) return;
if(bHover){
pge.DrawDecal(vPos + olc::vi2d(4, 4), pIconHover.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4);
} else {
pge.DrawDecal(vPos + olc::vi2d(4, 4), pIcon.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4);
}
}
void TransparentImageButton::DrawDecal(PixelGameEngine*pge){
if (!bVisible) return;
if(bHover){
pge->DrawDecal(vPos + olc::vi2d(4, 4), pIconHover.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4);
} else {
pge->DrawDecal(vPos + olc::vi2d(4, 4), pIcon.Decal(), iconScale,m_state!=State::Disabled?WHITE:WHITE/4);
}
};
#pragma endregion
#pragma region ImageCheckBox
ImageCheckBox::ImageCheckBox(olc::QuickGUI::Manager& manager, const olc::Renderable& gfx, const bool check, const olc::vf2d& pos, const olc::vf2d& size)

@ -210,8 +210,8 @@ namespace olc
pge->DrawPartialDecal(vScale * vBoom[y * spr.Sprite()->width + x].first * 2.0f, spr.Decal(), olc::vf2d(x, y), { 1, 1 }, vScale * 2.0f, olc::PixelF(1.0f, 1.0f, 1.0f, std::min(1.0f, std::max(4.0f - fParticleTime, 0.0f))));
}
olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2022");
pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2022", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f));
olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2023");
pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2023", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f));
return true;
}

@ -180,6 +180,7 @@ namespace olc
// 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 DrawShadowStringPropDecal(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);
@ -633,6 +634,11 @@ namespace olc
pge->DrawShadowStringDecal(WorldToScreen(pos), sText, col, shadowCol, scale * m_vWorldScale * m_vRecipPixel, shadowSizeFactor);
}
void TransformedView::DrawShadowStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::Pixel shadowCol, const olc::vf2d & scale, const float shadowSizeFactor)
{
pge->DrawShadowStringPropDecal(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);

@ -1108,8 +1108,9 @@ namespace olc
void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
olc::vi2d GetTextSize(const std::string& s);
// Draws a single line of text - non-monospaced
void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
void DrawShadowStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, const Pixel shadowCol = olc::BLACK, const olc::vf2d& scale = { 1.0f, 1.0f },const float shadowSizeFactor=1);
olc::vi2d GetTextSizeProp(const std::string& s);
// Decal Quad functions
@ -3520,6 +3521,17 @@ namespace olc
SetPixelMode(m);
}
void PixelGameEngine::DrawShadowStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, const Pixel shadowCol, const olc::vf2d& scale,const float shadowSizeFactor){
for(float y=-shadowSizeFactor;y<=shadowSizeFactor+0.1;y+=shadowSizeFactor/2){
for(float x=-shadowSizeFactor;x<=shadowSizeFactor+0.1;x+=shadowSizeFactor/2){
if(x!=0||y!=0){
DrawStringProp(pos.x+x,pos.y+y, sText, shadowCol,int(scale.x));
}
}
}
DrawStringProp(pos.x,pos.y, sText, col,int(scale.x));
}
void PixelGameEngine::SetPixelMode(Pixel::Mode m)
{ nPixelMode = m; }

@ -147,6 +147,12 @@ namespace olc::utils
return m_bWorldBoundary;
}
inline bool ReachedTarget() const
{
float dist=sqrt(pow(m_vPosition.x-GetTarget().x,2)+pow(m_vPosition.y-GetTarget().y,2));
return dist<=4;
}
// Get the world boundary rectangle position
inline const olc::vf2d& GetWorldBoundaryPosition() const
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 MiB

After

Width:  |  Height:  |  Size: 24 MiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.
Loading…
Cancel
Save