|
|
|
#include "Scenario.h"
|
|
|
|
#include "TileManager.h"
|
|
|
|
#include "olcUTIL_Geometry2D.h"
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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();});
|
|
|
|
}
|
|
|
|
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];
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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.");
|
|
|
|
if(box.bPressed){
|
|
|
|
state=1;
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
case 1:{
|
|
|
|
DisplayBox("Don't think it'll be that easy to get through this one...");
|
|
|
|
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.");
|
|
|
|
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;
|
|
|
|
}
|