#include "pause.h" #include #include #include #include #include #include #include using namespace DFHack; using namespace Pausing; using namespace df::enums; std::unordered_set PlayerLock::locks; std::unordered_set AnnouncementLock::locks; namespace pausing { AnnouncementLock announcementLock("monitor"); PlayerLock playerLock("monitor"); const size_t announcement_flag_arr_size = sizeof(decltype(df::announcements::flags)) / sizeof(df::announcement_flags); bool state_saved = false; // indicates whether a restore state is ok bool saved_states[announcement_flag_arr_size]; // state to restore bool locked_states[announcement_flag_arr_size]; // locked state (re-applied each frame) bool allow_player_pause = true; // toggles player pause ability using df::global::ui; using namespace df::enums; struct player_pause_hook : df::viewscreen_dwarfmodest { typedef df::viewscreen_dwarfmodest interpose_base; DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set* input)) { if ((ui->main.mode == ui_sidebar_mode::Default) && !allow_player_pause) { input->erase(interface_key::D_PAUSE); } INTERPOSE_NEXT(feed)(input); } }; IMPLEMENT_VMETHOD_INTERPOSE(player_pause_hook, feed); } using namespace pausing; template inline bool any_lock(Locks locks) { return std::any_of(locks.begin(), locks.end(), [](Lock* lock) { return lock->isLocked(); }); } template inline bool only_lock(Locks locks, LockT* this_lock) { return std::all_of(locks.begin(), locks.end(), [&](Lock* lock) { if (lock == this_lock) { return lock->isLocked(); } return !lock->isLocked(); }); } template inline bool only_or_none_locked(Locks locks, LockT* this_lock) { for (auto &L: locks) { if (L == this_lock) { continue; } if (L->isLocked()) { return false; } } return true; } template inline bool reportLockedLocks(color_ostream &out, Locks locks) { out.color(DFHack::COLOR_YELLOW); for (auto &L: locks) { if (L->isLocked()) { out.print("Lock: '%s'\n", L->name.c_str()); } } out.reset_color(); return true; } bool AnnouncementLock::captureState() { if (only_or_none_locked(locks, this)) { for (size_t i = 0; i < announcement_flag_arr_size; ++i) { locked_states[i] = df::global::d_init->announcements.flags[i].bits.PAUSE; } return true; } return false; } void AnnouncementLock::lock() { Lock::lock(); captureState(); } bool AnnouncementLock::isAnyLocked() const { return any_lock(locks); } bool AnnouncementLock::isOnlyLocked() const { return only_lock(locks, this); } void AnnouncementLock::reportLocks(color_ostream &out) { reportLockedLocks(out, locks); } bool PlayerLock::isAnyLocked() const { return any_lock(locks); } bool PlayerLock::isOnlyLocked() const { return only_lock(locks, this); } void PlayerLock::reportLocks(color_ostream &out) { reportLockedLocks(out, locks); } bool World::DisableAnnouncementPausing() { if (!announcementLock.isAnyLocked()) { for (auto& flag : df::global::d_init->announcements.flags) { flag.bits.PAUSE = false; //out.print("pause: %d\n", flag.bits.PAUSE); } return true; } return false; } bool World::SaveAnnouncementSettings() { if (!announcementLock.isAnyLocked()) { for (size_t i = 0; i < announcement_flag_arr_size; ++i) { saved_states[i] = df::global::d_init->announcements.flags[i].bits.PAUSE; } state_saved = true; return true; } return false; } bool World::RestoreAnnouncementSettings() { if (!announcementLock.isAnyLocked() && state_saved) { for (size_t i = 0; i < announcement_flag_arr_size; ++i) { df::global::d_init->announcements.flags[i].bits.PAUSE = saved_states[i]; } return true; } return false; } bool World::EnablePlayerPausing() { if (!playerLock.isAnyLocked()) { allow_player_pause = true; } return allow_player_pause; } bool World::DisablePlayerPausing() { if (!playerLock.isAnyLocked()) { allow_player_pause = false; } return !allow_player_pause; } bool World::IsPlayerPausingEnabled() { return allow_player_pause; } void World::Update() { static bool did_once = false; if (!did_once) { did_once = true; INTERPOSE_HOOK(player_pause_hook, feed).apply(); } if (announcementLock.isAnyLocked()) { for (size_t i = 0; i < announcement_flag_arr_size; ++i) { df::global::d_init->announcements.flags[i].bits.PAUSE = locked_states[i]; } } }