summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'core/src')
-rw-r--r--core/src/disposition.cpp25
-rw-r--r--core/src/participant.cpp35
-rw-r--r--core/src/turn_order.cpp225
3 files changed, 285 insertions, 0 deletions
diff --git a/core/src/disposition.cpp b/core/src/disposition.cpp
new file mode 100644
index 0000000..4eec33e
--- /dev/null
+++ b/core/src/disposition.cpp
@@ -0,0 +1,25 @@
+#include "turns/core/disposition.hpp"
+
+#include <glibmm/i18n.h>
+
+namespace turns::core
+{
+
+ auto presentation_name_for(disposition value) -> Glib::ustring
+ {
+ switch (value)
+ {
+ case disposition::neutral:
+ return _("Neutral");
+ case disposition::friendly:
+ return _("Friendly");
+ case disposition::hostile:
+ return _("Hostile");
+ case disposition::secret:
+ return _("Secret");
+ default:
+ return _("Unknown disposition value");
+ }
+ }
+
+} // namespace turns::core \ No newline at end of file
diff --git a/core/src/participant.cpp b/core/src/participant.cpp
new file mode 100644
index 0000000..45b02bd
--- /dev/null
+++ b/core/src/participant.cpp
@@ -0,0 +1,35 @@
+#include "turns/core/participant.hpp"
+
+#include <typeinfo>
+#include <utility>
+
+#include <glibmm/class.h>
+#include <glibmm/refptr.h>
+
+namespace turns::core
+{
+ auto participant::create(Glib::ustring name, float priority, core::disposition disposition) -> Glib::RefPtr<participant>
+ {
+ return Glib::make_refptr_for_instance(new participant{name, priority, disposition});
+ }
+
+ participant::participant()
+ : Glib::ObjectBase{typeid(participant)}
+ , Glib::Object{}
+ {
+ }
+
+ participant::participant(Glib::ustring name, float priority, core::disposition disposition)
+ : participant()
+ {
+ m_name = name;
+ m_priority = priority;
+ m_disposition = disposition;
+ }
+
+ auto participant::operator<=>(participant const & other) const noexcept -> std::partial_ordering
+ {
+ return m_priority <=> other.m_priority;
+ }
+
+} // namespace turns::core \ No newline at end of file
diff --git a/core/src/turn_order.cpp b/core/src/turn_order.cpp
new file mode 100644
index 0000000..ae3511e
--- /dev/null
+++ b/core/src/turn_order.cpp
@@ -0,0 +1,225 @@
+#include "turns/core/turn_order.hpp"
+
+#include "turns/core/participant.hpp"
+
+#include <algorithm>
+#include <compare>
+#include <limits>
+#include <typeinfo>
+
+#include <glibmm/refptr.h>
+
+namespace turns::core
+{
+
+ namespace
+ {
+ auto constexpr comparator = [](auto lhs, auto rhs) {
+ return *lhs > *rhs;
+ };
+
+ auto constexpr equal_comparator = [](auto lhs, auto rhs) {
+ return (lhs->get_name() == rhs->get_name()) && (lhs->get_priority() && rhs->get_priority());
+ };
+ } // namespace
+
+ /** Construction */
+
+ turn_order::turn_order()
+ : Glib::ObjectBase{typeid(turn_order)}
+ , Gio::ListModel{}
+ {
+ }
+
+ auto turn_order::create() -> Glib::RefPtr<turn_order>
+ {
+ return Glib::make_refptr_for_instance(new turn_order{});
+ }
+
+ /** Queries */
+
+ auto turn_order::is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>
+ {
+ return m_is_empty.get_proxy();
+ }
+
+ auto turn_order::has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>
+ {
+ return m_has_next.get_proxy();
+ }
+
+ auto turn_order::has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>
+ {
+ return m_has_previous.get_proxy();
+ }
+
+ auto turn_order::is_running() const -> Glib::PropertyProxy_ReadOnly<is_running_type>
+ {
+ return m_is_running.get_proxy();
+ }
+
+ auto turn_order::round_number() const -> Glib::PropertyProxy_ReadOnly<round_number_type>
+ {
+ return m_round_number.get_proxy();
+ }
+
+ /** Modifiers */
+
+ auto turn_order::add(Glib::ustring const & name, float priority, disposition disposition) -> void
+ {
+ auto entry = participant::create(name, priority, disposition);
+ entry->priority().signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &turn_order::handle_priority_changed), entry));
+ auto position = std::distance(m_data.cbegin(), insert(entry));
+ items_changed(position, 0, 1);
+
+ if (get_n_items() == 1)
+ {
+ m_is_empty = false;
+ m_has_next = true;
+ }
+ }
+
+ auto turn_order::clear() -> void
+ {
+ m_is_running = false;
+ m_is_empty = true;
+ m_has_next = false;
+ m_has_previous = false;
+ m_active.reset();
+ m_round_number = invalid_round_number;
+
+ auto old_size = get_n_items();
+ m_data.clear();
+ items_changed(0, old_size, 0);
+ }
+
+ auto turn_order::next() -> void
+ {
+ auto old_active = *m_active;
+ m_active = m_active.transform([this](auto index) { return (index + 1) % get_n_items(); });
+
+ m_has_previous = true;
+ m_data[old_active]->is_active() = false;
+ m_data[*m_active]->is_active() = true;
+
+ if (m_active == 0)
+ {
+ m_round_number = m_round_number + 1;
+ }
+ }
+
+ auto turn_order::previous() -> void
+ {
+ if (!(m_has_previous && m_is_running))
+ {
+ return;
+ }
+
+ auto old_active = *m_active;
+ m_active = m_active.transform([this](auto index) { return index ? index - 1 : get_n_items() - 1; });
+
+ m_has_previous = m_round_number > 0 || m_active > 0;
+ m_data[old_active]->is_active() = false;
+ m_data[*m_active]->is_active() = true;
+
+ if (m_active == 0 && m_round_number > 0)
+ {
+ m_round_number = m_round_number - 1;
+ }
+ }
+
+ auto turn_order::remove(unsigned index) -> void
+ {
+ if (index >= get_n_items())
+ {
+ return;
+ }
+
+ auto position = m_data.begin() + index;
+ m_data.erase(position);
+ items_changed(index, 1, 0);
+ if (get_n_items() == 0)
+ {
+ m_is_empty = true;
+ m_is_running = false;
+ m_has_next = false;
+ }
+ }
+
+ auto turn_order::start() -> void
+ {
+ if (!m_active)
+ {
+ m_active = 0;
+ m_data[*m_active]->is_active() = true;
+ }
+ if (m_round_number == invalid_round_number)
+ {
+ m_round_number = 0;
+ }
+ m_is_running = true;
+ }
+
+ auto turn_order::stop() -> void
+ {
+ m_is_running = false;
+ }
+
+ /** ListModel implementation */
+
+ auto turn_order::get_item_type_vfunc() -> GType
+ {
+ return participant::get_type();
+ }
+
+ auto turn_order::get_n_items_vfunc() -> unsigned
+ {
+ return m_data.size();
+ }
+
+ auto turn_order::get_item_vfunc(unsigned position) -> void *
+ {
+ if (position >= get_n_items())
+ {
+ return nullptr;
+ }
+ auto item = m_data[position];
+ item->reference();
+ return item->gobj();
+ }
+
+ /** Signal handlers */
+
+ auto turn_order::handle_priority_changed(value_type entry) -> void
+ {
+ auto original_position = find(entry);
+ auto original_index = distance(m_data.cbegin(), original_position);
+ auto target_position = std::ranges::upper_bound(m_data, entry, comparator);
+ if (original_position == target_position)
+ {
+ return;
+ }
+
+ m_data.erase(original_position);
+ auto inserted_position = insert(entry);
+ items_changed(0, get_n_items(), get_n_items());
+ if (m_active == original_index)
+ {
+ m_active = distance(m_data.cbegin(), inserted_position);
+ m_has_previous = m_round_number > 0 || m_active > 0;
+ }
+ }
+
+ /** Data management */
+
+ auto turn_order::find(value_type entry) const -> const_iterator
+ {
+ return std::ranges::find(m_data, entry);
+ }
+
+ auto turn_order::insert(value_type entry) -> const_iterator
+ {
+ return m_data.insert(std::ranges::upper_bound(m_data, entry, comparator), entry);
+ }
+
+} // namespace turns::core \ No newline at end of file