Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// Headers
#include "audio.h"
#include "audio_midi.h"
#include "options.h"
#include "system.h"
#include "baseui.h"
#include "player.h"
Expand Down Expand Up @@ -48,7 +49,7 @@ int EmptyAudio::BGM_GetTicks() const {
}

// Time since BGM_Play was called, works for everything except MIDI
return (Player::GetFrames() - bgm_starttick + 1) / Game_Clock::GetTargetGameFps();
return (Player::GetFrames() - bgm_starttick + 1) / DEFAULT_FPS;
}

void EmptyAudio::vGetConfig(Game_ConfigAudio&) const {
Expand All @@ -57,7 +58,7 @@ void EmptyAudio::vGetConfig(Game_ConfigAudio&) const {

bool EmptyAudio::BGM_PlayedOnce() const {
// 5 seconds, arbitrary
return BGM_GetTicks() > (Game_Clock::GetTargetGameFps() * 5);
return BGM_GetTicks() > (DEFAULT_FPS * 5);
}

EmptyAudio::EmptyAudio(const Game_ConfigAudio& cfg) : AudioInterface(cfg) {
Expand Down
8 changes: 7 additions & 1 deletion src/fps_overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "fps_overlay.h"
#include "game_clock.h"
#include "bitmap.h"
#include "options.h"
#include "utils.h"
#include "input.h"
#include "font.h"
Expand All @@ -39,7 +40,12 @@ FpsOverlay::FpsOverlay() :

void FpsOverlay::UpdateText() {
auto fps = Utils::RoundTo<int>(Game_Clock::GetFPS());
text = "FPS: " + std::to_string(fps);
text = fmt::format("FPS: {}", fps);

if (Game_Clock::GetTargetGameFps() != DEFAULT_FPS) {
text += fmt::format(" | TPS: {}", Game_Clock::GetTargetGameFps());
}

fps_dirty = true;
}

Expand Down
36 changes: 27 additions & 9 deletions src/game_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,25 @@ class Game_Clock {
template <typename R, typename P>
static void SleepFor(std::chrono::duration<R,P> dt);

/** Get the target frames per second for the game simulation */
static constexpr int GetTargetGameFps();
/**
* Get the target frames per second for the game simulation.
* Use this for everything that must run at the speed of the game.
* Use DEFAULT_FPS for framerate independent behaviours such as global
* timers.
*/
static int GetTargetGameFps();

/**
* Set the target frames per second for the game simulation
* @param fps new game fps
*/
static void SetTargetGameFps(int fps);

/** Get the amount of time each logical frame should take */
static constexpr duration GetTargetGameTimeStep();
static duration GetTargetGameTimeStep();

/** Get the timestep for a given frames per second value */
static constexpr duration TimeStepFromFps(int fps);
static duration TimeStepFromFps(int fps);

/** Get the name of the underlying clock type */
static constexpr const char* Name();
Expand Down Expand Up @@ -114,6 +125,7 @@ class Game_Clock {
time_point frame_time;
duration frame_accumulator;
duration max_frame_accumulator = std::chrono::duration_cast<duration>(std::chrono::milliseconds(200));
int target_fps = DEFAULT_FPS;
float speed = 1.0;
float fps = 0.0;
int frame = 0;
Expand All @@ -125,15 +137,21 @@ inline Game_Clock::time_point Game_Clock::now() {
return clock::now();
}

constexpr int Game_Clock::GetTargetGameFps() {
return DEFAULT_FPS;
inline int Game_Clock::GetTargetGameFps() {
return data.target_fps;
}

inline void Game_Clock::SetTargetGameFps(int fps) {
// Prevent game from becoming unplayable
fps = std::clamp<int>(fps, 10, 500);
data.target_fps = fps;
}

constexpr Game_Clock::duration Game_Clock::GetTargetGameTimeStep() {
inline Game_Clock::duration Game_Clock::GetTargetGameTimeStep() {
return TimeStepFromFps(GetTargetGameFps());
}

constexpr Game_Clock::duration Game_Clock::TimeStepFromFps(int fps) {
inline Game_Clock::duration Game_Clock::TimeStepFromFps(int fps) {
auto ns = std::chrono::nanoseconds(std::chrono::seconds(1)) / fps;
return std::chrono::duration_cast<Game_Clock::duration>(ns);
}
Expand All @@ -160,7 +178,7 @@ inline float Game_Clock::GetFPS() {
}

inline bool Game_Clock::NextGameTimeStep() {
constexpr auto dt = GetTargetGameTimeStep();
auto dt = GetTargetGameTimeStep();
if (data.frame_accumulator < dt) {
return false;
}
Expand Down
102 changes: 94 additions & 8 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "game_windows.h"
#include "json_helper.h"
#include "maniac_patch.h"
#include "options.h"
#include "spriteset_map.h"
#include "sprite_character.h"
#include "scene_gameover.h"
Expand Down Expand Up @@ -479,7 +480,7 @@ void Game_Interpreter::Update(bool reset_loop_count) {
if (_keyinput.timed) {
// 10 per second
Main_Data::game_variables->Set(_keyinput.time_variable,
(_keyinput.wait_frames * 10) / Game_Clock::GetTargetGameFps());
(_keyinput.wait_frames * 10) / DEFAULT_FPS);
Game_Map::SetNeedRefreshForVarChange(_keyinput.time_variable);
RuntimePatches::OnVariableChanged(_keyinput.time_variable);
}
Expand Down Expand Up @@ -5056,17 +5057,102 @@ bool Game_Interpreter::CommandManiacSetGameOption(lcf::rpg::EventCommand const&
return true;
}

int operation = com.parameters[1];
//int value = ValueOrVariable(com.parameters[0], com.parameters[2]);
const auto option_type = com.parameters[1];

switch (operation) {
case 2: // Change Picture Limit (noop, we support arbitrary amount of pictures)
switch (option_type) {
case 0: { // .runWhenInactive or .pauseWhenInactive
const bool run_when_inactive = (ValueOrVariable(com.parameters[0], com.parameters[2]) != 0);

if (DisplayUi) {
DisplayUi->SetPauseWhenFocusLost(!run_when_inactive);
}
return true;
}
case 1: { // FatalMix: .fatal fps, testPlayMode, fastForwardText
int fps = ValueOrVariable(com.parameters[0], com.parameters[2]); // Game Speed
const int test_play_mode = com.parameters[3] & 3; // 0: Keep, 1: Off, 2: On
const bool enable_fast_forward_text = (com.parameters[3] & 16) != 0;

// Implementation difference: We reset the frame rate when the game ends
if (fps > 0) {
Game_Clock::SetTargetGameFps(fps);
}

switch (test_play_mode) {
case 1:
Player::debug_flag = false;
break;
default:
Output::Warning("Maniac SetGameOption: Operation {} not supported", operation);
case 2:
Player::debug_flag = true;
break;
}

// Implementation difference: We always enable this while in TestPlay mode
// This option only configures the behaviour outside of TestPlay
Main_Data::game_system->SetFastForwardText(enable_fast_forward_text);
return true;
}
case 2: { // .picLimit limit
// Change Picture Limit (noop, we support arbitrary amount of pictures)
const int pic_limit = ValueOrVariable(com.parameters[0], com.parameters[2]);
Output::Debug("Maniac SetGameOption: Picture Limit set to {}", pic_limit);
return true;
}
case 3: { // .fullFrame, .oneFifth, .oneThird, .oneHalf
// Frame Skip
const int skip_mode = com.parameters[2];
int percentage = 100;
switch (skip_mode) {
case 1:
percentage = 20;
break; // 1/5
case 2:
percentage = 33;
break; // 1/3
case 3:
percentage = 50;
break; // 1/2
}
Player::SetFrameSkip(percentage);
return true;
}
case 4: { // .mouse.disableMsgProcession value
// Left Mouse button can continue messages
const bool enable_mouse_for_messages = (ValueOrVariable(com.parameters[0], com.parameters[2]) == 0);
Main_Data::game_system->SetMessageMouseEnabled(enable_mouse_for_messages);
return true;
}
case 5: { // .btlOrigin position
// Battle UI position
// 0: center, 1: topLeft, 2: bottomLeft, 3: topRight, 4: bottomRight,
// 5: top, 6: bottom, 7: left, 8: right
const int battle_origin = com.parameters[2];

return true;
// TODO: This sets the rendering location for the battle scene
// Needs modifying all the drawing code in the battle system
Output::Warning("Maniac SetGameOption: Reposition Battle UI (position: {}) not implemented.", battle_origin);
Main_Data::game_system->SetBattleOrigin(battle_origin);
return true;
}
case 6: { // .animLimit limit
// Battle Animation Limit
Output::Warning("Maniac SetGameOption: Battle Animation limit not implemented.");
return true;
}
case 7: { // .winFaceSize width, height
const int width = ValueOrVariable(com.parameters[0], com.parameters[2]);
const int height = ValueOrVariable(com.parameters[0], com.parameters[3]);

Output::Warning("Maniac SetGameOption: Custom WinFaceSize ({}x{}) not implemented.", width, height);
// TODO: Values must be used in OnFaceReady. Maniacs appears to not hardcode 4 faces per line so this needs
// further testing
Main_Data::game_system->SetMessageFaceSize(width, height);
return true;
}
default:
Output::Warning("Maniac SetGameOption: Unknown Operation {}", static_cast<int>(option_type));
return true;
}
}

bool Game_Interpreter::CommandManiacControlStrings(lcf::rpg::EventCommand const& com) {
Expand Down
10 changes: 4 additions & 6 deletions src/game_quit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,18 @@ Game_Quit::Game_Quit()

void Game_Quit::Update() {
if (Scene::instance == nullptr || Scene::instance->type == Scene::Title || !Scene::Find(Scene::Title) || !Input::IsPressed(Input::RESET)) {
if (time_left != start_time) {
Reset();
}
Reset();
return;
}

window.SetVisible(true);

if (time_left > 0) {
--time_left;
time_left -= static_cast<double>(DEFAULT_FPS) / Game_Clock::GetTargetGameFps();
}

// FIXME Need to write the text every frame in case system graphic changes..
auto s = (time_left + DEFAULT_FPS - 1) / DEFAULT_FPS;
auto s = static_cast<int>(time_left + DEFAULT_FPS - 1) / DEFAULT_FPS;
window.SetText("Restarting in " + std::to_string(s) + " sec ...");
window.Update();
}
Expand All @@ -63,5 +61,5 @@ void Game_Quit::OnResolutionChange() {

void Game_Quit::Reset() {
window.SetVisible(false);
time_left = DEFAULT_FPS * num_seconds;
time_left = DEFAULT_FPS * num_seconds + (Player::debug_flag ? 0 : 1);
}
4 changes: 2 additions & 2 deletions src/game_quit.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ class Game_Quit {
void Reset();

Window_Help window;
int time_left = 0;
double time_left = 0;
};

inline bool Game_Quit::ShouldQuit() const {
return time_left == 0;
return time_left <= 0;
}

#endif
1 change: 0 additions & 1 deletion src/game_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,4 +648,3 @@ bool Game_System::IsMessageTransparent() {

return data.message_transparent != 0;
}

53 changes: 53 additions & 0 deletions src/game_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,19 @@ class Game_System {
/** @return Whether the game was loaded from a savegame in the current frame */
bool IsLoadedThisFrame() const;

void SetFastForwardText(bool enabled);
bool IsFastForwardText() const;

void SetMessageMouseEnabled(bool disabled);
bool IsMessageMouseEnabled() const;

void SetBattleOrigin(int origin);
int GetBattleOrigin() const;

void SetMessageFaceSize(int width, int height);
int GetMessageFaceWidth() const;
int GetMessageFaceHeight() const;

private:
std::string InelukiReadLink(Filesystem_Stream::InputStream& stream);

Expand All @@ -453,6 +466,10 @@ class Game_System {
Color bg_color = Color{ 0, 0, 0, 255 };
bool bgm_pending = false;
int loaded_frame_count = 0;

// Game options that are not saved
bool maniac_fast_forward_text = false;
bool message_mouse = false;
};

inline bool Game_System::HasSystemGraphic() {
Expand Down Expand Up @@ -662,5 +679,41 @@ inline bool Game_System::GetAllowMenu() {
return data.menu_allowed;
}

inline void Game_System::SetFastForwardText(bool enabled) {
maniac_fast_forward_text = enabled;
}

inline bool Game_System::IsFastForwardText() const {
return maniac_fast_forward_text;
}

inline void Game_System::SetMessageMouseEnabled(bool enabled) {
message_mouse = enabled;
}

inline bool Game_System::IsMessageMouseEnabled() const {
return message_mouse;
}

inline void Game_System::SetBattleOrigin(int origin) {
data.maniac_battle_origin = origin;
}

inline int Game_System::GetBattleOrigin() const {
return data.maniac_battle_origin;
}

inline void Game_System::SetMessageFaceSize(int width, int height) {
data.maniac_message_face_width = width;
data.maniac_message_face_height = height;
}

inline int Game_System::GetMessageFaceWidth() const {
return data.maniac_message_face_width;
}

inline int Game_System::GetMessageFaceHeight() const {
return data.maniac_message_face_height;
}

#endif
3 changes: 3 additions & 0 deletions src/input_buttons.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace Input {
DEBUG_THROUGH,
DEBUG_SAVE,
DEBUG_ABORT_EVENT,
DEBUG_MESSAGE_FAST_FORWARD,
SETTINGS_MENU,
TOGGLE_FPS,
TAKE_SCREENSHOT,
Expand Down Expand Up @@ -115,6 +116,7 @@ namespace Input {
"DEBUG_THROUGH",
"DEBUG_SAVE",
"DEBUG_ABORT_EVENT",
"DEBUG_MESSAGE_FAST_FORWARD",
"SETTINGS_MENU",
"TOGGLE_FPS",
"TAKE_SCREENSHOT",
Expand Down Expand Up @@ -160,6 +162,7 @@ namespace Input {
"(Test Play) Walk through walls",
"(Test Play) Open the save menu",
"(Test Play) Aborts current active event",
"(Test Play) Fast forward through messages",
"Open this settings menu",
"Toggle the FPS display",
"Take a screenshot",
Expand Down
Loading
Loading