Implemented unlocking of areas via clearing stages. Game fade in/out for state transitions. Asset loading for visual novel assets. Visual Novel command execution code implemented. Visual Novel basic rendering and input handling enabled.

pull/28/head
sigonasr2 1 year ago
parent 3601e8b83a
commit a7f13e0077
  1. 49
      Crawler/Crawler.cpp
  2. 9
      Crawler/Crawler.h
  3. 1
      Crawler/Crawler.vcxproj
  4. 3
      Crawler/Crawler.vcxproj.filters
  5. 25
      Crawler/GameState.cpp
  6. 7
      Crawler/GameState.h
  7. 10
      Crawler/LevelCompleteWindow.cpp
  8. 69
      Crawler/Menu.cpp
  9. 10
      Crawler/Menu.h
  10. 9
      Crawler/OverworldMapLevelWindow.cpp
  11. 12
      Crawler/State_OverworldMap.cpp
  12. 9
      Crawler/State_Story.cpp
  13. 14
      Crawler/Unlock.cpp
  14. 7
      Crawler/Unlock.h
  15. 2
      Crawler/Version.h
  16. 120
      Crawler/VisualNovel.cpp
  17. 23
      Crawler/VisualNovel.h
  18. 0
      Crawler/assets/characters/Red Stone.png
  19. 9
      Crawler/assets/config/configuration.txt
  20. 8
      Crawler/assets/config/gfx/themes.txt
  21. 10
      Crawler/assets/config/story/characters.txt

@ -59,6 +59,7 @@ SUCH DAMAGE.
#include "Test.h"
#include "ItemDrop.h"
#include "VisualNovel.h"
#include "util.h"
INCLUDE_EMITTER_LIST
@ -79,6 +80,7 @@ InputGroup Crawler::KEY_RIGHT;
InputGroup Crawler::KEY_UP;
InputGroup Crawler::KEY_DOWN;
InputGroup Crawler::KEY_ATTACK;
InputGroup Crawler::KEY_CONFIRM;
float Crawler::SIZE_CHANGE_SPEED=1;
@ -132,6 +134,9 @@ Crawler::Crawler()
bool Crawler::OnUserCreate(){
InitializeDefaultKeybinds();
VisualNovel::Initialize();
InitializeLevels();
player=std::make_unique<Warrior>();
@ -185,8 +190,6 @@ bool Crawler::OnUserCreate(){
Unlock::Initialize();
ItemDrop::Initialize();
VisualNovel::Initialize();
ValidateGameStatus(); //Checks to make sure everything has been initialized properly.
return true;
@ -195,10 +198,13 @@ bool Crawler::OnUserCreate(){
bool Crawler::OnUserUpdate(float fElapsedTime){
fElapsedTime=std::clamp(fElapsedTime,0.f,1/30.f); //HACK fix. We can't have a negative time. Although using a more precise system clock should make this never occur. Also make sure if the game is too slow we advance by only 1/30th of a second.
levelTime+=fElapsedTime;
GameState::STATE->OnUserUpdate(this);
if(!GamePaused()){
GameState::STATE->OnUserUpdate(this);
}
RenderWorld(GetElapsedTime());
GameState::STATE->Draw(this);
RenderMenu();
RenderFadeout();
RenderVersionInfo();
return true;
}
@ -1390,6 +1396,10 @@ void Crawler::InitializeLevel(std::string mapFile,MapName map){
}
for(ConnectionPoint&cp:State_OverworldMap::connections){
if(VisualNovel::storyLevelData.count(cp.map)){ //Visual novel story data for story levels.
cp.levelDataExists=true;
break;
}
if(LEVEL_NAMES.count(cp.map)&&&MapHelper::MapFromString(cp.map)==&MAP_DATA[map]){
MAP_DATA[map].name=cp.name;
for(int spawn:MAP_DATA[map].spawns){
@ -1914,6 +1924,8 @@ void Crawler::InitializeDefaultKeybinds(){
KEY_UP.AddKeybind({KEY,W});
KEY_DOWN.AddKeybind({KEY,DOWN});
KEY_DOWN.AddKeybind({KEY,S});
KEY_CONFIRM.AddKeybind({MOUSE,Mouse::LEFT});
KEY_CONFIRM.AddKeybind({KEY,ENTER});
}
void Crawler::SetBossNameDisplay(std::string name,float time){
@ -1977,7 +1989,7 @@ void Crawler::ReduceBossEncounterMobCount(){
}
void Crawler::RenderMenu(){
if(Menu::stack.size()>0){
if(!GamePaused()&&Menu::stack.size()>0){
Menu::stack.back()->Update(this);
}
if(Menu::stack.size()>0){
@ -2029,7 +2041,7 @@ void Crawler::InitializeGraphics(){
std::sort(mappedKeys.begin(),mappedKeys.end(),[](std::pair<std::string,size_t>&key1,std::pair<std::string,size_t>&key2){return key1.second<key2.second;});
for(auto&key:mappedKeys){
std::string themeName=key.first;
std::string imgPath=DATA["Themes"][themeName]["Name"].GetString();
std::string imgPath=DATA["Themes"][themeName]["filename"].GetString();
Renderable&img=GFX["theme_img_directory"_S+imgPath+".png"];
img.Load("GFX_Prefix"_S+"theme_img_directory"_S+imgPath+".png");
Renderable&sourceImg=img;
@ -2064,6 +2076,12 @@ void Crawler::InitializeGraphics(){
}
}
for(std::string img:VisualNovel::graphicsToLoad){
Renderable&image=GFX[img];
image.Load("GFX_Prefix"_S+img);
}
std::cout<<VisualNovel::graphicsToLoad.size()<<" images for visual novel engine have been loaded."<<std::endl;
Menu::themes.SetInitialized();
std::cout<<Menu::themes.size()<<" themes have been loaded."<<std::endl;
GFX.SetInitialized();
@ -2170,6 +2188,25 @@ bool Crawler::UseLoadoutItem(int slot){
void Crawler::ClearLoadoutItem(int slot){
if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+").");
loadout[slot].amt=0;
loadout[slot].it=nullptr;
}
void Crawler::RenderFadeout(){
uint8_t alpha=0;
if(fadeOutDuration>0){
fadeOutDuration=std::max(0.f,fadeOutDuration-GetElapsedTime());
if(fadeOutDuration==0){
GameState::_ChangeState(transitionState);
}
alpha=uint8_t(util::lerp(0,255,1-(fadeOutDuration/fadeOutTotalTime)));
}else
if(fadeInDuration>0){
fadeInDuration=std::max(0.f,fadeInDuration-GetElapsedTime());
alpha=uint8_t(util::lerp(255,0,1-(fadeInDuration/fadeOutTotalTime)));
}
FillRectDecal({0,0},GetScreenSize(),{0,0,0,alpha});
}
bool Crawler::GamePaused(){
return fadeOutDuration>0;
}

@ -45,14 +45,17 @@ SUCH DAMAGE.
#include "TMXParser.h"
#include "olcUTIL_DataFile.h"
#include "Key.h"
#include "GameState.h"
class Crawler : public olc::PixelGameEngine
{
friend class GameState;
friend class State_GameRun;
friend class sig::Animation;
std::unique_ptr<Player>player;
public:
Pathfinding pathfinder;
static InputGroup KEY_CONFIRM;
static InputGroup KEY_ATTACK;
static InputGroup KEY_LEFT;
static InputGroup KEY_RIGHT;
@ -96,6 +99,10 @@ private:
int totalBossEncounterMobs=0;
int chapter=1; //We start at chapter 1.
std::array<Item,3>loadout;
float fadeOutDuration=0;
float fadeOutTotalTime=0;
float fadeInDuration=0;
States::State transitionState=States::State::GAME_RUN;
std::vector<Monster>monstersToBeSpawned;
@ -182,6 +189,8 @@ public:
bool UseLoadoutItem(int slot);
//Blanks out this loadout item.
void ClearLoadoutItem(int slot);
void RenderFadeout();
bool GamePaused();
struct TileGroupData{
vi2d tilePos;

@ -429,7 +429,6 @@
<Text Include="assets\config\MonsterStrategies.txt" />
<Text Include="assets\config\Player.txt" />
<Text Include="assets\config\story\Chapter 1.txt" />
<Text Include="assets\config\story\characters.txt" />
<Text Include="Crawler_Story_Chapter_1 (2).txt" />
<Text Include="Crawler_System_Overview.txt" />
<Text Include="NewClasses.txt" />

@ -533,9 +533,6 @@
<Text Include="Crawler_Story_Chapter_1 (2).txt">
<Filter>Documentation\Story</Filter>
</Text>
<Text Include="assets\config\story\characters.txt">
<Filter>Configurations\Story</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<Image Include="assets\heart.ico">

@ -53,14 +53,23 @@ void GameState::Initialize(){
GameState::ChangeState(States::OVERWORLD_MAP);
}
void GameState::ChangeState(States::State newState){
GameState*prevState=STATE;
if(!states.count(newState)){
ERR("WARNING! State not defined for state "<<newState<<"!")
}
STATE=states.at(newState);
game->camera.SetTarget(game->GetPlayer()->GetPos());
STATE->OnStateChange(prevState);
void GameState::_ChangeState(States::State newState){
GameState*prevState=STATE;
if(!states.count(newState)){
ERR("WARNING! State not defined for state "<<newState<<"!")
}
STATE=states.at(newState);
game->camera.SetTarget(game->GetPlayer()->GetPos());
STATE->OnStateChange(prevState);
}
void GameState::ChangeState(States::State newState,float fadeOutDuration){
if(fadeOutDuration>0){
game->fadeOutDuration=game->fadeOutTotalTime=game->fadeInDuration=fadeOutDuration;
game->transitionState=newState;
}else{
_ChangeState(newState);
}
}
GameState::~GameState(){}

@ -1,3 +1,4 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
@ -29,6 +30,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#pragma endregion
#pragma once
#include <map>
#include <iostream>
@ -47,6 +49,9 @@ namespace States{
};
class GameState{
friend class Crawler;
private:
static void _ChangeState(States::State newState);
public:
inline static GameState*STATE=nullptr;
inline static std::map<States::State,GameState*>states;
@ -55,5 +60,5 @@ public:
virtual void OnStateChange(GameState*prevState)=0;
virtual void OnUserUpdate(Crawler*game)=0;
virtual void Draw(Crawler*game)=0;
static void ChangeState(States::State newState);
static void ChangeState(States::State newState,float fadeOutDuration=0);
};

@ -37,6 +37,8 @@ SUCH DAMAGE.
#include "MenuComponent.h"
#include "InventoryScrollableWindowComponent.h"
#include "PopupMenuLabel.h"
#include "Unlock.h"
#include "State_OverworldMap.h"
INCLUDE_game
@ -64,10 +66,16 @@ void Menu::InitializeLevelCompleteWindow(){
levelCompleteWindow->AddComponent("Stage Loot Outline",stageLootOutline);
levelCompleteWindow->AddComponent("Stage Loot Label",stageLootLabel);
levelCompleteWindow->AddComponent("Stage Loot Window",stageLootWindow);
auto nextButtonAction=[](MenuFuncData data){
Unlock::UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map);
GameState::ChangeState(States::OVERWORLD_MAP,0.5f);
return true;
};
MenuComponent*detailsOutline=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE);
MenuLabel*detailsExpGain=NEW MenuLabel(LEVEL_COMPLETE,{{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND);
MenuComponent*nextButton=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,144},{71,32}},"Next",DO_NOTHING);
MenuComponent*nextButton=NEW MenuComponent(LEVEL_COMPLETE,{{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction);
levelCompleteWindow->AddComponent("Level Details Outline",detailsOutline);
levelCompleteWindow->AddComponent("Level EXP Gain Outline",detailsExpGain);

@ -63,6 +63,7 @@ MenuType Menu::lastMenuTypeCreated;
std::string Menu::lastRegisteredComponent;
bool Menu::cover;
INCLUDE_game
INCLUDE_GFX
extern vi2d WINDOW_SIZE;
@ -301,9 +302,9 @@ void Menu::Update(Crawler*game){
void Menu::Draw(Crawler*game){
if(GetCurrentTheme().IsScaled()){
DrawScaledWindowBackground(game,pos);
DrawScaledWindowBackground(game,pos,size,GetRenderColor());
}else{
DrawTiledWindowBackground(game,pos);
DrawTiledWindowBackground(game,pos,size,GetRenderColor());
}
game->SetDrawTarget(r.Sprite());
@ -340,9 +341,9 @@ void Menu::Draw(Crawler*game){
}
if(GetCurrentTheme().IsScaled()){
DrawScaledWindowBorder(game,pos);
DrawScaledWindowBorder(game,pos,size,GetRenderColor());
}else{
DrawTiledWindowBorder(game,pos);
DrawTiledWindowBorder(game,pos,size,GetRenderColor());
}
if(draggingComponent!=nullptr){
@ -535,69 +536,69 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
}
}
void Menu::DrawScaledWindowBorder(Crawler*game,vf2d menuPos){
void Menu::DrawScaledWindowBorder(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor){
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
//Upper-Left
game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{patchSize.x*0,patchSize.y*0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{patchSize.x*0,patchSize.y*0},patchSize,renderColor);
//Upper-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{patchSize.x*2,patchSize.y*0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{patchSize.x*2,patchSize.y*0},patchSize,renderColor);
//Bottom-Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{patchSize.x*0,patchSize.y*2},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{patchSize.x*0,patchSize.y*2},patchSize,renderColor);
//Bottom-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{patchSize.x*2,patchSize.y*2},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{patchSize.x*2,patchSize.y*2},patchSize,renderColor);
//Top
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{patchSize.x*1,patchSize.y*0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{patchSize.x*1,patchSize.y*0},patchSize,renderColor);
//Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{patchSize.x*0,patchSize.y*1},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{patchSize.x*0,patchSize.y*1},patchSize,renderColor);
//Right
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{patchSize.x*2,patchSize.y*1},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{patchSize.x*2,patchSize.y*1},patchSize,renderColor);
//Bottom
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{patchSize.x*1,patchSize.y*2},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{patchSize.x*1,patchSize.y*2},patchSize,renderColor);
}
void Menu::DrawTiledWindowBorder(Crawler*game,vf2d menuPos){
void Menu::DrawTiledWindowBorder(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor){
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
//Upper-Left
game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{0,0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos-patchSize,patchSize,GetPatchPart(0,0).Decal(),{0,0},patchSize,renderColor);
//Upper-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{0,0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,-patchSize.y},patchSize,GetPatchPart(2,0).Decal(),{0,0},patchSize,renderColor);
//Bottom-Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{0,0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,size.y},patchSize,GetPatchPart(0,2).Decal(),{0,0},patchSize,renderColor);
//Bottom-Right
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{0,0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,size.y},patchSize,GetPatchPart(2,2).Decal(),{0,0},patchSize,renderColor);
//Top
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{0,0},vf2d{size.x,patchSize.y},GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{0,-patchSize.y},vf2d{size.x,patchSize.y},GetPatchPart(1,0).Decal(),{0,0},vf2d{size.x,patchSize.y},renderColor);
//Left
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{0,0},vf2d{patchSize.x,size.y},GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{-patchSize.x,0},vf2d{patchSize.x,size.y},GetPatchPart(0,1).Decal(),{0,0},vf2d{patchSize.x,size.y},renderColor);
//Right
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{0,0},vf2d{patchSize.x,size.y},GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{size.x,0},vf2d{patchSize.x,size.y},GetPatchPart(2,1).Decal(),{0,0},vf2d{patchSize.x,size.y},renderColor);
//Bottom
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{0,0},vf2d{size.x,patchSize.y},GetRenderColor());
game->DrawPartialDecal(menuPos+vf2d{0,size.y},vf2d{size.x,patchSize.y},GetPatchPart(1,2).Decal(),{0,0},vf2d{size.x,patchSize.y},renderColor);
}
void Menu::DrawScaledWindowBackground(Crawler*game,vf2d menuPos){
void Menu::DrawScaledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor){
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
//Center
if(GetCurrentTheme().HasBackground()){
Decal*back=GetCurrentTheme().GetBackground();
game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size(),GetRenderColor());
game->DrawPartialDecal(menuPos,size,back,{0,0},back->sprite->Size(),renderColor);
}else{
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{patchSize.x*1,patchSize.y*1},patchSize,renderColor);
}
}
void Menu::DrawTiledWindowBackground(Crawler*game,vf2d menuPos){
void Menu::DrawTiledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor){
vf2d patchSize={"Interface.9PatchSize"_f[0],"Interface.9PatchSize"_f[1]};
//Center
if(GetCurrentTheme().HasBackground()){
Decal*back=GetCurrentTheme().GetBackground();
game->DrawPartialDecal(menuPos,size,back,{0,0},size,GetRenderColor());
game->DrawPartialDecal(menuPos,size,back,{0,0},size,renderColor);
}else{
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{0,0},patchSize,GetRenderColor());
game->DrawPartialDecal(menuPos,size,GetPatchPart(1,1).Decal(),{0,0},patchSize,renderColor);
}
}
@ -701,4 +702,14 @@ void Menu::CleanupAllMenus(){
Menu::menus.clear();
}
void Menu::Cleanup(){}
void Menu::Cleanup(){}
void Menu::DrawThemedWindow(vf2d menuPos,vf2d size,Pixel renderColor){
if(GetCurrentTheme().IsScaled()){
DrawScaledWindowBackground(game,menuPos,size,renderColor);
DrawScaledWindowBorder(game,menuPos,size,renderColor);
}else{
DrawTiledWindowBackground(game,menuPos,size,renderColor);
DrawTiledWindowBorder(game,menuPos,size,renderColor);
}
}

@ -105,6 +105,8 @@ public:
//Returns the last menu type created and last registered component, in case a component is detected as memory leaking, provides this information to each component for safety.
static std::pair<MenuType,std::string>GetMemoryLeakReportInfo();
virtual void Cleanup();
static void DrawThemedWindow(vf2d menuPos,vf2d size,Pixel renderColor=WHITE);
private:
Menu(vf2d pos,vf2d size);
static MenuType lastMenuTypeCreated;
@ -128,10 +130,10 @@ private:
static Renderable&GetPatchPart(int x,int y);
void KeyboardButtonNavigation(Crawler*game,vf2d menuPos);
void DrawScaledWindowBackground(Crawler*game,vf2d menuPos);
void DrawTiledWindowBackground(Crawler*game,vf2d menuPos);
void DrawScaledWindowBorder(Crawler*game,vf2d menuPos);
void DrawTiledWindowBorder(Crawler*game,vf2d menuPos);
static void DrawScaledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
static void DrawTiledWindowBackground(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
static void DrawScaledWindowBorder(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
static void DrawTiledWindowBorder(Crawler*game,vf2d menuPos,vf2d size,Pixel renderColor);
//This triggers if we use a keyboard/controller input to try and select some off-screen menu item. We should ideally follow the menu cursor.
bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton);

@ -50,15 +50,6 @@ void Menu::InitializeOverworldMapLevelWindow(){
Menu*levelSelectWindow=CreateMenu(OVERWORLD_LEVEL_SELECT,{game->GetScreenSize().x-game->GetScreenSize().x/3.f,24},windowSize);
State_OverworldMap*overworldMap=(State_OverworldMap*)GameState::states[States::OVERWORLD_MAP]; //HACK ALERT!! We're going to make an assumption that we are in the overworld map state.
//Map&loadedMap=MapHelper::MapFromString(overworldMap->GetCurrentConnectionPoint().map);
//std::set<int>&spawns=loadedMap.spawns;
/*int yOffset=40;
for(int key:spawns){
MenuLabel*testLabel=new MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,float(yOffset)},{windowSize.x,24}},MONSTER_DATA[key].GetDisplayName());
yOffset+=28;
levelSelectWindow->AddComponent(MONSTER_DATA[key].GetDisplayName()+" Display Label",testLabel);
}*/
MenuLabel*chapterLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
MenuLabel*stageLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);

@ -41,6 +41,7 @@ SUCH DAMAGE.
#include "drawutil.h"
#include "MenuLabel.h"
#include "EncountersSpawnListScrollableWindowComponent.h"
#include "VisualNovel.h"
INCLUDE_MONSTER_LIST
INCLUDE_game
@ -51,6 +52,7 @@ State_OverworldMap::State_OverworldMap(){
SetStageMarker("Stage I-I"); //Eventually we will load the game from a file and this will not be necessary. We just set it to this for now.
}
void State_OverworldMap::OnStateChange(GameState*prevState){
game->LoadLevel(WORLD_MAP);
if(Menu::IsMenuOpen()){
Menu::CloseAllMenus();
}
@ -84,7 +86,7 @@ void State_OverworldMap::OnUserUpdate(Crawler*game){
for(int neighborInd:currentConnectionPoint->neighbors){
if(neighborInd==-1)continue;
ConnectionPoint&neighbor=ConnectionPointFromIndex(neighborInd);
if(Unlock::IsUnlocked(neighbor.name)&&&cp==&neighbor){
if(Unlock::IsUnlocked(neighbor.unlockCondition)&&&cp==&neighbor){
currentConnectionPoint=&neighbor;
playerTargetPos=currentConnectionPoint->rect.pos+currentConnectionPoint->rect.size/2+vf2d{0,16};
float angleTo=util::angleTo(game->GetPlayer()->GetPos(),playerTargetPos);
@ -141,6 +143,10 @@ ConnectionPoint&State_OverworldMap::GetCurrentConnectionPoint(){
}
void State_OverworldMap::StartLevel(){
game->LoadLevel(LEVEL_NAMES.at(State_OverworldMap::GetCurrentConnectionPoint().map));
GameState::ChangeState(States::GAME_RUN);
if(State_OverworldMap::GetCurrentConnectionPoint().map.starts_with("STORY")){
VisualNovel::LoadVisualNovel(State_OverworldMap::GetCurrentConnectionPoint().map);
}else{
game->LoadLevel(LEVEL_NAMES.at(State_OverworldMap::GetCurrentConnectionPoint().map));
GameState::ChangeState(States::GAME_RUN);
}
}

@ -33,11 +33,14 @@ SUCH DAMAGE.
#pragma endregion
#include "State_Story.h"
#include "VisualNovel.h"
#include "Menu.h"
void State_Story::OnStateChange(GameState*prevState){};
void State_Story::OnStateChange(GameState*prevState){
Menu::CloseAllMenus();
};
void State_Story::OnUserUpdate(Crawler*game){
VisualNovel::Update();
VisualNovel::novel.Update();
};
void State_Story::Draw(Crawler*game){
VisualNovel::Draw();
VisualNovel::novel.Draw();
};

@ -32,20 +32,26 @@ SUCH DAMAGE.
*/
#pragma endregion
#include "Unlock.h"
#include "State_OverworldMap.h"
std::set<std::string>Unlock::unlocks;
void Unlock::Initialize(){
UnlockArea("WORLD_MAP");
UnlockArea("CAMPAIGN_1_1");
}
void Unlock::UnlockArea(std::string unlock){
unlocks.insert(unlock);
void Unlock::UnlockArea(std::string mapName){
unlocks.insert(mapName);
}
bool Unlock::IsUnlocked(std::string unlock){
return unlocks.count(unlock);
bool Unlock::IsUnlocked(std::string mapName){
return unlocks.count(mapName);
}
bool Unlock::IsUnlocked(ConnectionPoint&cp){
return unlocks.count(cp.unlockCondition);
}
void Unlock::UnlockCurrentMap(){
UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map);
}

@ -41,7 +41,10 @@ class Unlock{
static std::set<std::string>unlocks;
static void Initialize();
public:
static void UnlockArea(std::string unlock);
static bool IsUnlocked(std::string unlock);
//Provide a map's actual name to trigger unlocks for all connected areas. You can get the current map you are on via State_OverworlMap::GetCurrentConnectionPoint().map
static void UnlockArea(std::string mapName);
//Uses the current map as the unlock criteria.
static void UnlockCurrentMap();
static bool IsUnlocked(std::string mapName);
static bool IsUnlocked(ConnectionPoint&cp);
};

@ -35,7 +35,7 @@ SUCH DAMAGE.
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 1
#define VERSION_BUILD 3172
#define VERSION_BUILD 3212
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -35,9 +35,16 @@ SUCH DAMAGE.
#include "GameState.h"
#include "Crawler.h"
#include <fstream>
#include "DEFINES.h"
#include "Unlock.h"
#include "Menu.h"
INCLUDE_game
INCLUDE_GFX
VisualNovel VisualNovel::novel;
safemap<std::string,std::vector<std::unique_ptr<Command>>>VisualNovel::storyLevelData;
std::set<std::string>VisualNovel::graphicsToLoad;
void VisualNovel::Initialize(){
for(int chapter=1;chapter<=6;chapter++){
@ -80,6 +87,17 @@ void VisualNovel::Initialize(){
case '{':{ //Start of a command.
auto&data=storyLevelData.at(currentStory);
auto AddImagesForLoading=[](std::vector<std::string>&arguments){
for(std::string&arg:arguments){
if(arg=="story_player_name"_S){
graphicsToLoad.insert("character_image_location"_S+"Player_F.png");
graphicsToLoad.insert("character_image_location"_S+"Player_M.png");
}else{
graphicsToLoad.insert("character_image_location"_S+arg+".png");
}
}
};
size_t spacePos=line.find(' ');
std::vector<std::string>arguments;
@ -97,12 +115,15 @@ void VisualNovel::Initialize(){
}else
if(line.find("{BACKGROUND")!=std::string::npos){//Background command
if(arguments.size()!=1)ERR("Arguments size is "<<arguments.size()<<". Expecting only 1 argument.")
graphicsToLoad.insert("story_background_image_location"_S+arguments[0]);
data.push_back(std::make_unique<BackgroundCommand>(arguments[0]));
}else
if(line.find("{LEFT")!=std::string::npos){//Left command
AddImagesForLoading(arguments);
data.push_back(std::make_unique<LeftCommand>(arguments));
}else
if(line.find("{RIGHT")!=std::string::npos){//Right command
AddImagesForLoading(arguments);
data.push_back(std::make_unique<RightCommand>(arguments));
}else
if(line.find("{PAUSE")!=std::string::npos){//Pause command
@ -141,13 +162,51 @@ void VisualNovel::Initialize(){
};
void VisualNovel::LoadVisualNovel(std::string storyLevelName){
novel.storyLevel=storyLevelName;
GameState::ChangeState(States::STORY);
novel.activeText="";
novel.leftCharacters.clear();
novel.rightCharacters.clear();
novel.backgroundFilename="";
novel.commands.clear();
for(std::unique_ptr<Command>&command:storyLevelData.at(storyLevelName)){
novel.commands.push_back(command.get());
}
GameState::ChangeState(States::STORY,0.5f);
novel.ExecuteNextCommand();
novel.prevTheme=Menu::GetCurrentTheme().GetThemeName();
Menu::themeSelection="Purple";
}
void VisualNovel::Update(){
if(game->KEY_CONFIRM.Pressed()){
novel.ExecuteNextCommand();
}
locationDisplayTime=std::max(0.f,locationDisplayTime-game->GetElapsedTime());
}
void VisualNovel::ExecuteNextCommand(){
if(commandIndex<commands.size()){
commandIndex++;
commands[commandIndex-1]->Execute(novel);
}else{
Unlock::UnlockCurrentMap();
Menu::themeSelection=novel.prevTheme;
GameState::ChangeState(States::OVERWORLD_MAP,0.5f);
}
}
void VisualNovel::Draw(){
if(backgroundFilename!=""){
game->DrawDecal({0,0},GFX["backgrounds/"+backgroundFilename].Decal());
}else{
game->FillRectDecal({0,0},game->GetScreenSize());
}
if(locationDisplayTime>0){
vi2d textSize=game->GetTextSizeProp(locationDisplayText)*2;
game->FillRectDecal(game->GetScreenSize()/2-textSize/2-vi2d{4,4},textSize+vi2d{8,8},BLACK);
game->DrawRectDecal(game->GetScreenSize()/2-textSize/2-vi2d{4,4},textSize+vi2d{8,8},WHITE);
game->DrawShadowStringPropDecal(game->GetScreenSize()/2-textSize/2,locationDisplayText,WHITE,VERY_DARK_BLUE,{2.f,2.f});
}
if(activeText.length()>0){
Menu::DrawThemedWindow({24.f,game->GetScreenSize().y-60.f},{48.f,-12.f});
Menu::DrawThemedWindow({24.f,game->GetScreenSize().y-48.f},{game->GetScreenSize().x-48.f,20.f});
}
}
VisualNovel::VisualNovel(){}
@ -155,60 +214,49 @@ VisualNovel::VisualNovel(){}
Command::Command(){}
void LocationCommand::Execute(VisualNovel&vn){
vn.locationDisplayTime=5.f;
vn.locationDisplayText=location;
vn.ExecuteNextCommand();
}
LocationCommand::LocationCommand(std::string location)
:location(location){
}
:location(location){}
void BackgroundCommand::Execute(VisualNovel&vn){
vn.backgroundFilename=backgroundFilename;
vn.ExecuteNextCommand();
}
BackgroundCommand::BackgroundCommand(std::string backgroundFilename)
:backgroundFilename(backgroundFilename){
}
:backgroundFilename(backgroundFilename){}
void LeftCommand::Execute(VisualNovel&vn){
vn.leftCharacters=characters;
vn.ExecuteNextCommand();
}
LeftCommand::LeftCommand(std::vector<std::string>characters)
:characters(characters){
}
:characters(characters){}
void RightCommand::Execute(VisualNovel&vn){
vn.rightCharacters=characters;
vn.ExecuteNextCommand();
}
RightCommand::RightCommand(std::vector<std::string>characters)
:characters(characters){
}
:characters(characters){}
void SpeakerCommand::Execute(VisualNovel&vn){
vn.speakerDisplayName=displayedName;
vn.actualSpeakerName=actualSpeakerName;
vn.ExecuteNextCommand();
}
SpeakerCommand::SpeakerCommand(std::string speaker)
:displayedName(speaker),actualSpeakerName(speaker){
}
:displayedName(speaker),actualSpeakerName(speaker){}
SpeakerCommand::SpeakerCommand(std::string displayedName,std::string speaker)
:displayedName(displayedName),actualSpeakerName(speaker){
}
:displayedName(displayedName),actualSpeakerName(speaker){}
void DialogCommand::Execute(VisualNovel&vn){
vn.activeText=dialog;
}
DialogCommand::DialogCommand(std::string dialog)
:dialog(dialog){
}
:dialog(dialog){}
void PauseCommand::Execute(VisualNovel&vn){
}
PauseCommand::PauseCommand(){
}
void PauseCommand::Execute(VisualNovel&vn){}
PauseCommand::PauseCommand(){}

@ -35,10 +35,12 @@ SUCH DAMAGE.
#include <vector>
#include <memory>
#include "safemap.h"
#include <set>
class VisualNovel;
class Command{
friend class VisualNovel;
virtual void Execute(VisualNovel&vn)=0;
protected:
Command();
@ -95,14 +97,30 @@ public:
};
class VisualNovel{
friend class State_Story;
friend class Crawler;
friend class Command;
friend class LocationCommand;
friend class BackgroundCommand;
friend class LeftCommand;
friend class RightCommand;
friend class SpeakerCommand;
friend class DialogCommand;
friend class PauseCommand;
std::string storyLevel;
std::string speakerDisplayName="";
std::string actualSpeakerName="";
std::string activeText;
std::vector<std::string>leftCharacters;
std::vector<std::string>rightCharacters;
std::string backgroundFilename;
std::vector<Command*>commands;
int commandIndex=0;
std::string locationDisplayText="";
float locationDisplayTime=0;
std::string prevTheme="";
static std::set<std::string>graphicsToLoad;
static safemap<std::string,std::vector<std::unique_ptr<Command>>>storyLevelData;
static VisualNovel novel;
@ -112,6 +130,7 @@ public:
VisualNovel(VisualNovel&&)=delete;
static void Initialize();
static void LoadVisualNovel(std::string storyLevelName);
static void Update();
static void Draw();
void ExecuteNextCommand();
void Update();
void Draw();
};

Before

Width:  |  Height:  |  Size: 1004 B

After

Width:  |  Height:  |  Size: 1004 B

@ -51,6 +51,15 @@ item_img_directory = items/
# Path to story files
story_directory = config/story/
# Path to character images
character_image_location = characters/
# Path to story backgrounds
story_background_image_location = backgrounds/
# The name substituted for the player in dialogs
story_player_name = You
# Whether or not to show individual data accesses from config data structure.
debug_access_options = 0

@ -30,7 +30,7 @@ Themes
BlueDefault
{
Name = 9patch
filename = 9patch
ButtonColor = 0,0,64,255
HighlightColor = 0,200,200,255
@ -43,7 +43,7 @@ Themes
}
Purple
{
Name = 9patch_2
filename = 9patch_2
ButtonColor = 40,16,71,255
HighlightColor = 192,128,238,255
@ -56,7 +56,7 @@ Themes
}
NicoPink
{
Name = 9patch_3
filename = 9patch_3
ButtonColor = 208,73,182,255
HighlightColor = 255,239,232,255
@ -69,7 +69,7 @@ Themes
}
NicoPinkTiled
{
Name = 9patch_4
filename = 9patch_4
ButtonColor = 208,73,182,255
HighlightColor = 255,239,232,255

@ -1,10 +0,0 @@
character_image_location = assets/characters
Characters
{
Player_F = player_f.png
Player_M = player_m.png
Sherman = sherman.png
Greg = greg.png
Red Stone = red_stone.png
}
Loading…
Cancel
Save