From 14c9a7048cb24599c113a83e0f493b76455aa7a5 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Mon, 12 Aug 2024 18:03:59 -0500 Subject: [PATCH] New events and fixes for reworked leaders - Add leader ethic, job, planet, and creator - Add leader changed ethic event - Add leader left country event - Add governed planet event - Fix governed sector event - Fix galcom and federation representation events - Change event texts to refer to actual leader classes - Don't list planet buildings with 0 counts --- .../dashboard_app/history_ledger.py | 19 ++- .../dashboard_app/templates/history_page.html | 107 ++++++++----- stellarisdashboard/datamodel.py | 26 ++- stellarisdashboard/parsing/timeline.py | 149 +++++++++++++----- 4 files changed, 218 insertions(+), 83 deletions(-) diff --git a/stellarisdashboard/dashboard_app/history_ledger.py b/stellarisdashboard/dashboard_app/history_ledger.py index 17c1b91..982721d 100644 --- a/stellarisdashboard/dashboard_app/history_ledger.py +++ b/stellarisdashboard/dashboard_app/history_ledger.py @@ -298,6 +298,12 @@ def collect_event_dicts(self, event_list, key_object): if event.end_date_days is not None: end_date = datamodel.days_to_date(event.end_date_days) is_active = event.end_date_days >= self._most_recent_date + description = event.description + if type(description) is str: + if description.startswith("{"): + description = game_info.render_name(description) + else: + description = game_info.lookup_key(description) event_dict = dict( country=event.country, start_date=start, @@ -310,7 +316,7 @@ def collect_event_dicts(self, event_list, key_object): planet=event.planet, faction=event.faction, target_country=event.target_country, - description=event.description, + description=description, fleet=event.fleet, ) event_dict = {k: v for (k, v) in event_dict.items() if v is not None} @@ -468,11 +474,16 @@ def leader_details(self, leader_model: datamodel.Leader) -> Dict[str, str]: country_url = self._get_url_for(leader_model.country) details = { "Leader Name": leader_model.rendered_name, - "Gender": game_info.convert_id_to_name(leader_model.gender), - "Species": leader_model.species.rendered_name, "Class": f"{game_info.convert_id_to_name(leader_model.leader_class)} in the {country_url}", "Subclass": f"{game_info.lookup_key(leader_model.subclass)}" or "None", "Traits": ", ".join(leader_model.rendered_traits), + "Species": leader_model.species.rendered_name, + "Gender": game_info.convert_id_to_name(leader_model.gender), + "Ethic": game_info.lookup_key(leader_model.ethic), + "Previous Position": game_info.lookup_key(f"job_{leader_model.job}") + if leader_model.job is not None else "None", + "Home Planet": self._get_url_for(leader_model.planet), + "Country of Origin": self._get_url_for(leader_model.creator), "Born": datamodel.days_to_date(leader_model.date_born), "Hired": datamodel.days_to_date(leader_model.date_hired), "Last active": datamodel.days_to_date( @@ -564,7 +575,7 @@ def planet_details(self, planet_model: datamodel.Planet): buildings[building.name] += building.count if buildings: details["Buildings"] = ", ".join( - f"{k}: {v}" for k, v in sorted(buildings.items()) + f"{k}: {v}" for k, v in sorted(buildings.items()) if v > 0 ) return details diff --git a/stellarisdashboard/dashboard_app/templates/history_page.html b/stellarisdashboard/dashboard_app/templates/history_page.html index cc9058e..c8fb96f 100644 --- a/stellarisdashboard/dashboard_app/templates/history_page.html +++ b/stellarisdashboard/dashboard_app/templates/history_page.html @@ -79,7 +79,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} relocated their capital to the {{ event["planet"].planetclass }} {{ links[event["planet"]] | safe }} @@ -94,7 +94,7 @@

{{title[object] | safe}}

The {{ links[event["country"]] | safe }} colonized the {{ event["planet"].planetclass }} {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system - {% if "leader" in event%} under Governor {{ links[event["leader"]] | safe}}{% endif %}. + {% if "leader" in event%} under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% endif %}.
@@ -178,7 +178,7 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %}Under ruler {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} prepared a new agenda "{{event["description"]}}".
@@ -188,7 +188,7 @@

{{title[object] | safe}}

{{event["start_date"]}}: - {% if "leader" in event %}Under ruler {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} launched the agenda "{{event["description"]}}".
@@ -207,8 +207,21 @@

{{title[object] | safe}}

{% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - Governor {{ links[event["leader"]] | safe }} governed the {{event["description"]}} sector{% if "planet" in event %} - from planet {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system{%endif%}. + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} + governed the {{event["description"]}} sector + from the planet {{ links[event["planet"]] | safe }} + in the {{ links[event["system"]] | safe }} system. + +
+ + {% elif event["event_type"] == "governed_planet" %} +
  • +
    + {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: + + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} + governed the planet {{ links[event["planet"]] | safe }} + in the {{ links[event["system"]] | safe }} system.
  • @@ -217,7 +230,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %}Ruler {{ links[event["leader"]] | safe}}{% else %}The {{ links[event["country"]] | safe}}{% endif %} + {% if "leader" in event %}{{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% else %}The {{ links[event["country"]] | safe}}{% endif %} enacted the "{{event["description"]}}" edict.
    @@ -227,7 +240,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %}Under ruler {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} enacted a new policy on {{event["description"]}}.
    @@ -237,7 +250,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %}Under ruler {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} + {% if "leader" in event %}Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %}The {% endif %} {{ links[event["country"]] | safe}} changed their policy on {{event["description"]}}.
    @@ -248,7 +261,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: {% if "leader" in event %} - Ruler {{ links[event["leader"]] | safe }} ascended the {{ links[event["country"]] | safe }} with "{{event["description"]}}". + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} ascended the {{ links[event["country"]] | safe }} with "{{event["description"]}}". {% else %} The {{ links[event["country"]] | safe }} ascended with "{{event["description"]}}". {% endif %} @@ -261,7 +274,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: {% if "leader" in event %} - Ruler {{ links[event["leader"]] | safe }} reformed the {{ links[event["country"]] | safe }} government: + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} reformed the {{ links[event["country"]] | safe }} government: {% else %} Government reforms in the {{ links[event["country"]] | safe}}: {% endif %} @@ -274,7 +287,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} adopted the "{{ event["description"]}}" tradition. @@ -313,7 +326,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} established first contact with the {{ links[event["target_country"]] | safe }}. @@ -325,7 +338,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} declared rivalry against the {{ links[event["target_country"]] | safe }}. @@ -338,7 +351,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} received a rivalry declaration from the {{ links[event["target_country"]] | safe }}. @@ -351,7 +364,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} revoked border access to the {{ links[event["target_country"]] | safe }}. @@ -382,7 +395,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a defensive pact with the {{ links[event["target_country"]] | safe }}. @@ -395,7 +408,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a research agreement with the {{ links[event["target_country"]] | safe }}. @@ -408,7 +421,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a commercial pact with the {{ links[event["target_country"]] | safe }}. @@ -421,7 +434,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a migration treaty with the {{ links[event["target_country"]] | safe }}. @@ -434,7 +447,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered a non-aggression pact with the {{ links[event["target_country"]] | safe }}. @@ -446,7 +459,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} and {{ links[event["target_country"]] | safe }} are now allied in the "{{ event["description"] }}" federation. @@ -456,18 +469,18 @@

    {{title[object] | safe}}

    {% elif event["event_type"] == "envoy_community" %}
  • - {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: + {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent envoy {{ links[event["leader"]] | safe }} to increase their diplomatic weight in the galactic community. + The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to increase their diplomatic weight in the galactic community.
  • {% elif event["event_type"] == "envoy_federation" %}
  • - {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: + {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent envoy {{ links[event["leader"]] | safe }} to improve the cohesion of the {{ event["description"] }}. + The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to improve the cohesion of the {{ event["description"] }}.
  • @@ -476,7 +489,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent envoy {{ links[event["leader"]] | safe }} to improve relations with the {{ links[event["target_country"]] | safe }}. + The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to improve relations with the {{ links[event["target_country"]] | safe }}.
    @@ -485,7 +498,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - The {{ links[event["country"]] | safe }} sent envoy {{ links[event["leader"]] | safe }} to harm relations with the {{ links[event["target_country"]] | safe }}. + The {{ links[event["country"]] | safe }} sent {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe }} to harm relations with the {{ links[event["target_country"]] | safe }}.
    @@ -494,7 +507,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} joined the Galactic Community. @@ -506,7 +519,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} joined the Galactic Council. @@ -518,7 +531,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} left the Galactic Community. @@ -530,7 +543,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} left the Galactic Council. @@ -543,7 +556,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: Finished construction of {{ event["description"] }} in the {{ links[event["system"]] | safe }} system{% if "leader" in event %}, - under Governor {{ links[event["leader"]] | safe}}{% endif %}. + under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}{% endif %}.
    @@ -556,13 +569,33 @@

    {{title[object] | safe}}

    + {% elif event["event_type"] == "leader_left_country" %} +
  • +
    + {{event["start_date"]}}: + + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}} + left the service of the {{ links[event["country"]] | safe }}. + +
    +
  • + {% elif event["event_type"] == "leader_changed_ethic" %} +
  • +
    + {{event["start_date"]}}: + + {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}} + changed their ethic to {{ event["description"] }}. + +
    +
  • {% elif event["event_type"] == "sector_creation" %}
  • {{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} created the {{ event["description"] }} sector{% if "planet" in event %} @@ -586,7 +619,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} entered the {{ links[event["war"]] | safe }} war{{ event["description"] }}{% if event["target_country"] %} {{ links[event["target_country"]] | safe}}{% endif %}. @@ -599,7 +632,7 @@

    {{title[object] | safe}}

    {{event["start_date"]}}: - {% if "leader" in event %} Under ruler {{ links[event["leader"]] | safe}}, the + {% if "leader" in event %} Under the rule of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% else %} The {% endif %} {{ links[event["country"]] | safe }} made peace in the {{ links[event["war"]] | safe }} conflict. @@ -620,7 +653,7 @@

    {{title[object] | safe}}

    {% if event["is_active"] %}(A){% endif %} {{event["start_date"]}}{% if event["end_date"] != null %} - {{event["end_date"]}}{%endif%}: - {% if "leader" in event %} Under governor {{ links[event["leader"]] | safe}}, the {% endif %}{{ links[event["country"]] | safe }} + {% if "leader" in event %} under the governorship of {{ event["leader"].leader_class.capitalize() }} {{ links[event["leader"]] | safe}}, the {% endif %}{{ links[event["country"]] | safe }} terraformed the planet {{ links[event["planet"]] | safe }} in the {{ links[event["system"]] | safe }} system {{ event["description"] }}. diff --git a/stellarisdashboard/datamodel.py b/stellarisdashboard/datamodel.py index 59b984b..d049a9b 100644 --- a/stellarisdashboard/datamodel.py +++ b/stellarisdashboard/datamodel.py @@ -14,7 +14,7 @@ from alembic.autogenerate import produce_migrations from alembic.migration import MigrationContext from alembic.operations import Operations -from alembic.operations.ops import ModifyTableOps +from alembic.operations.ops import ModifyTableOps, CreateForeignKeyOp from stellarisdashboard import config, game_info @@ -45,11 +45,15 @@ def get_db_session(game_id) -> sqlalchemy.orm.Session: stack = [migrations.upgrade_ops] while stack: elem = stack.pop(0) + print(elem) if use_batch and isinstance(elem, ModifyTableOps): with operations.batch_alter_table( elem.table_name, schema=elem.schema ) as batch_ops: for table_elem in elem.ops: + if isinstance(table_elem, CreateForeignKeyOp): + # see alembic bug about constraint names: https://github.com/sqlalchemy/alembic/issues/1195 + table_elem.constraint_name = table_elem.local_cols[0] batch_ops.invoke(table_elem) elif hasattr(elem, "ops"): stack.extend(elem.ops) @@ -173,6 +177,10 @@ class HistoricalEventType(enum.Enum): fleet_command = enum.auto() gained_trait = enum.auto() lost_trait = enum.auto() + # more further down (to preserve auto enum): + # - leader_changed_ethic + # - leader_left_country + # - governed_planet # empire progress: researched_technology = enum.auto() @@ -238,6 +246,11 @@ class HistoricalEventType(enum.Enum): conquered_system = enum.auto() lost_system = enum.auto() + # more leader events + leader_changed_ethic = enum.auto() + leader_left_country = enum.auto() + governed_planet = enum.auto() + def __str__(self): return self.name @@ -285,9 +298,11 @@ def scope(self): HistoricalEventType.sector_creation, HistoricalEventType.planetary_unrest, HistoricalEventType.governed_sector, + HistoricalEventType.governed_planet, HistoricalEventType.councilor, HistoricalEventType.faction_leader, HistoricalEventType.leader_recruited, + HistoricalEventType.leader_left_country, HistoricalEventType.leader_died, HistoricalEventType.researched_technology, HistoricalEventType.tradition, @@ -299,6 +314,7 @@ def scope(self): return HistoricalEventScope.country elif self in { HistoricalEventType.level_up, + HistoricalEventType.leader_changed_ethic, }: return HistoricalEventScope.leader elif self in { @@ -1452,6 +1468,12 @@ class Leader(Base): first_name = Column(String(80)) second_name = Column(String(80)) + # background info + creator_id = Column(ForeignKey(Country.country_id)) + planet_id = Column(ForeignKey("planet.planet_id")) + ethic = Column(String(80)) + job = Column(String(80)) + species_id = Column(ForeignKey(Species.species_id)) leader_class = Column(String(80)) gender = Column(String(20)) @@ -1470,6 +1492,8 @@ class Leader(Base): country = relationship( "Country", back_populates="leaders", foreign_keys=[country_id], post_update=True ) + creator = relationship("Country", foreign_keys=[creator_id], post_update=True) + planet = relationship("Planet", foreign_keys=[planet_id], post_update=True) species = relationship("Species") fleet_command = relationship("Fleet", back_populates="commander") historical_events = relationship( diff --git a/stellarisdashboard/parsing/timeline.py b/stellarisdashboard/parsing/timeline.py index c19ae8f..4468961 100644 --- a/stellarisdashboard/parsing/timeline.py +++ b/stellarisdashboard/parsing/timeline.py @@ -191,8 +191,8 @@ def _data_processors(self) -> Iterable["AbstractGamestateDataProcessor"]: yield GalacticMarketProcessor() yield InternalMarketProcessor() yield SpeciesProcessor() - yield LeaderProcessor() yield PlanetProcessor() + yield LeaderProcessor() yield SectorColonyEventProcessor() yield PlanetUpdateProcessor() yield RulerEventProcessor() @@ -210,6 +210,11 @@ def _data_processors(self) -> Iterable["AbstractGamestateDataProcessor"]: yield PopStatsProcessor() +# LeaderProcessor needs to refer to this before PlanetProcessor has been declared +# For consistency, maybe we should move all IDs up above here +PLANET_PROCESSOR_ID = "planet_models" + + class AbstractGamestateDataProcessor(abc.ABC): ID = "abstract" DEPENDENCIES = [] @@ -1070,7 +1075,7 @@ def _get_or_add_species(self, species_id_in_game: int, species_data: Dict): class LeaderProcessor(AbstractGamestateDataProcessor): ID = "leader" - DEPENDENCIES = [CountryProcessor.ID, SpeciesProcessor.ID] + DEPENDENCIES = [CountryProcessor.ID, SpeciesProcessor.ID, PLANET_PROCESSOR_ID] def __init__(self): super().__init__() @@ -1088,6 +1093,8 @@ def data(self): def extract_data_from_gamestate(self, dependencies): countries = dependencies[CountryProcessor.ID] self._species_dict, _ = dependencies[SpeciesProcessor.ID] + self._planets_by_ingame_id = dependencies.get(PlanetProcessor.ID) + self._countries_by_ingame_id = dependencies.get(CountryProcessor.ID) db_active_leaders = {} db_inactive_leaders = {} @@ -1110,7 +1117,8 @@ def _check_known_leaders(self, db_active_leaders: Dict[int, datamodel.Leader]): leader.last_date = self._basic_info.date_in_days else: leader_dict = gs_active_leaders[ingame_id] - self._update_leader_attributes(leader=leader, leader_dict=leader_dict) + country = self._countries_by_ingame_id.get(leader_dict.get("country")) + self._update_leader_attributes(country=country, leader=leader, leader_dict=leader_dict) if not leader.is_active: country_data = leader.country.get_most_recent_data() self._session.add( @@ -1170,6 +1178,12 @@ def _add_new_leader( + self._random_instance.randint(-15, 15) ) subclass, leader_traits = self._get_leader_traits(leader_dict) + ethic = leader_dict.get("ethic", "ethic_neutral") + job = leader_dict.get("job") + planet_id = leader_dict.get("planet") + planet = self._planets_by_ingame_id.get(planet_id) + creator_id = leader_dict.get("creator") + creator = self._countries_by_ingame_id.get(creator_id) leader = datamodel.Leader( country=country_model, leader_id_in_game=leader_id, @@ -1180,9 +1194,13 @@ def _add_new_leader( is_active=True, subclass=subclass, leader_traits=leader_traits, + ethic=ethic, + job=job, + planet=planet, + creator=creator, ) self._update_leader_attributes( - leader=leader, leader_dict=leader_dict + country=country_model, leader=leader, leader_dict=leader_dict ) # sets additional attributes country_data = country_model.get_most_recent_data() event = datamodel.HistoricalEvent( @@ -1191,8 +1209,8 @@ def _add_new_leader( leader=leader, start_date_days=date_hired, end_date_days=self._basic_info.date_in_days, - event_is_known_to_player=country_data is not None - and country_data.attitude_towards_player.reveals_economy_info(), + event_is_known_to_player=(country_model is not None and country_model.is_player) + or (country_data is not None and country_data.attitude_towards_player.reveals_economy_info()), ) self._session.add(event) return leader @@ -1206,17 +1224,15 @@ def get_leader_name(self, leader_dict): last_name = dump_name(name_dict.get("second_name", "")) return first_name, last_name - def _update_leader_attributes(self, leader: datamodel.Leader, leader_dict): - if "pre_ruler_class" in leader_dict: - leader_class = leader_dict.get("pre_ruler_class", "unknown class") - else: - leader_class = leader_dict.get("class", "unknown class") + def _update_leader_attributes(self, country: datamodel.Country, leader: datamodel.Leader, leader_dict): + leader_class = leader_dict.get("class", "unknown class") leader_gender = leader_dict.get("gender", "other") first_name, second_name = self.get_leader_name(leader_dict) level = leader_dict.get("level", -1) species_id = leader_dict.get("species", -1) leader_species = self._species_dict.get(species_id) subclass, leader_traits = self._get_leader_traits(leader_dict) + ethic = leader_dict.get("ethic", "ethic_neutral") if leader_species is None: logger.warning( f"{self._basic_info.logger_str} Invalid species ID {species_id} for leader {leader_dict}" @@ -1229,12 +1245,13 @@ def _update_leader_attributes(self, leader: datamodel.Leader, leader_dict): or leader.gender != leader_gender or leader.species != leader_species or leader.leader_traits != leader_traits + or leader.country != country + or leader.ethic != ethic ): hist_event_kwargs = dict( - country=leader.country, + country=country, start_date_days=self._basic_info.date_in_days, leader=leader, - event_is_known_to_player=leader.country.is_player, ) if leader.last_level != level: self._session.add( @@ -1242,6 +1259,7 @@ def _update_leader_attributes(self, leader: datamodel.Leader, leader_dict): **hist_event_kwargs, event_type=datamodel.HistoricalEventType.level_up, db_description=self._get_or_add_shared_description(str(level)), + event_is_known_to_player=country is not None and country.is_player, ) ) if leader.leader_traits != leader_traits: @@ -1263,8 +1281,42 @@ def _update_leader_attributes(self, leader: datamodel.Leader, leader_dict): **hist_event_kwargs, event_type=event_type, db_description=self._get_or_add_shared_description(trait), + event_is_known_to_player=country is not None and country.is_player, ) ) + if leader.country != country: + if leader.country is not None: + country_data = leader.country.get_most_recent_data() + self._session.add( + datamodel.HistoricalEvent( + event_type=datamodel.HistoricalEventType.leader_left_country, + country=leader.country, + leader=leader, + start_date_days=self._basic_info.date_in_days, + event_is_known_to_player=(leader.country is not None and leader.country.is_player) + or (country_data is not None and country_data.attitude_towards_player.reveals_economy_info()), + ) + ) + if country is not None: + country_data = country.get_most_recent_data() + self._session.add( + datamodel.HistoricalEvent( + **hist_event_kwargs, + event_type=datamodel.HistoricalEventType.leader_recruited, + end_date_days=self._basic_info.date_in_days, + event_is_known_to_player=(country is not None and country.is_player) + or (country_data is not None and country_data.attitude_towards_player.reveals_economy_info()), + ) + ) + if leader.ethic != ethic: + self._session.add( + datamodel.HistoricalEvent( + **hist_event_kwargs, + event_type=datamodel.HistoricalEventType.leader_changed_ethic, + db_description=self._get_or_add_shared_description(ethic), + event_is_known_to_player=country is not None and country.is_player, + ) + ) leader.last_level = level leader.first_name = first_name @@ -1274,6 +1326,8 @@ def _update_leader_attributes(self, leader: datamodel.Leader, leader_dict): leader.gender = leader_gender leader.species = leader_species leader.leader_traits = leader_traits + leader.country = country + leader.ethic = ethic self._session.add(leader) def _get_leader_traits(self, leader_dict) -> (str, str): @@ -1312,7 +1366,7 @@ def strip_level(t: str) -> str: class PlanetProcessor(AbstractGamestateDataProcessor): - ID = "planet_models" + ID = PLANET_PROCESSOR_ID DEPENDENCIES = [SystemProcessor.ID] def __init__(self): @@ -1571,36 +1625,31 @@ def extract_data_from_gamestate(self, dependencies): sector_description = self._get_or_add_shared_description( text=dump_name(sector_info.get("name", "Unnamed")) ) - governor_model = self._leaders_dict.get(sector_info.get("governor")) + sector_capital = self._planets_dict.get( + sector_info.get("local_capital") + ) + sector_capital_planet_dict = self._gamestate_dict["planets"]["planet"].get(sector_info.get("local_capital")) + governor_model = self._leaders_dict.get(sector_capital_planet_dict.get("governor")) if sector_capital_planet_dict is not None else None for system_id in sector_info.get("systems", []): self._history_add_planetary_events_within_sector( - country_model, system_id, governor_model + country_model, system_id, governor_model, sector_capital, sector_description ) if system_id in unprocessed_systems: unprocessed_systems.remove(system_id) - sector_capital = self._planets_dict.get( - sector_info.get("local_capital") - ) - if governor_model is not None and sector_capital is not None: - self._history_add_or_update_governor_sector_events( - country_model, - sector_capital, - governor_model, - sector_description, - ) - for system_id in unprocessed_systems: self._history_add_planetary_events_within_sector( - country_model, system_id, None + country_model, system_id, None, None, None ) def _history_add_planetary_events_within_sector( self, country_model: datamodel.Country, system_id: int, - governor: Optional[datamodel.Leader], + sector_governor: Optional[datamodel.Leader], + sector_capital: Optional[datamodel.Planet], + sector_description: Optional[datamodel.SharedDescription], ): system_model = self._systems_dict.get(system_id) if system_model is None: @@ -1633,6 +1682,8 @@ def _history_add_planetary_events_within_sector( planet_model = self._planets_dict.get(planet_id) if planet_model is None: continue + planet_governor = self._leaders_dict.get(planet_dict.get("governor")) + governor = planet_governor if planet_governor is not None else sector_governor if is_colonizable: self._history_add_or_update_colonization_events( country_model, system_model, planet_model, planet_dict, governor @@ -1652,6 +1703,14 @@ def _history_add_planetary_events_within_sector( event_is_known_to_player=country_model.has_met_player(), ) ) + if planet_governor is not None : + self._history_add_or_update_governor_events( + country_model, + planet_model, + sector_capital, + planet_governor, + sector_description, + ) def _history_add_or_update_colonization_events( self, @@ -1762,18 +1821,20 @@ def _history_add_or_update_terraforming_events( matching_event.end_date_days = self._basic_info.date_in_days - 1 self._session.add(matching_event) - def _history_add_or_update_governor_sector_events( + def _history_add_or_update_governor_events( self, - country_model, - sector_capital: datamodel.Planet, + country_model: datamodel.Country, + planet: datamodel.Planet, + sector_capital: Optional[datamodel.Planet], governor: datamodel.Leader, - sector_description: datamodel.SharedDescription, + sector_description: Optional[datamodel.SharedDescription], ): - # check if governor was ruling same sector before => update date and return + event_type = datamodel.HistoricalEventType.governed_sector if sector_capital == planet else datamodel.HistoricalEventType.governed_planet + # check if governor was ruling same planet/sector before => update date and return event = ( self._session.query(datamodel.HistoricalEvent) .filter_by( - event_type=datamodel.HistoricalEventType.governed_sector, + event_type=event_type, db_description=sector_description, ) .order_by(datamodel.HistoricalEvent.end_date_days.desc()) @@ -1783,12 +1844,12 @@ def _history_add_or_update_governor_sector_events( event is not None and event.leader == governor and event.end_date_days > self._basic_info.date_in_days - 5 * 360 - ): # if the governor ruled this sector less than 5 years ago, re-use the event... + ): # if the governor ruled this planet/sector less than 5 years ago, re-use the event... event.end_date_days = self._basic_info.date_in_days - 1 else: country_data = country_model.get_most_recent_data() event = datamodel.HistoricalEvent( - event_type=datamodel.HistoricalEventType.governed_sector, + event_type=event_type, leader=governor, country=country_model, db_description=sector_description, @@ -1798,9 +1859,9 @@ def _history_add_or_update_governor_sector_events( and country_data.attitude_towards_player.reveals_economy_info(), ) - if event.planet is None and sector_capital is not None: - event.planet = sector_capital - event.system = sector_capital.system + if event.planet is None and planet is not None: + event.planet = planet + event.system = planet.system self._session.add(event) @@ -3032,7 +3093,7 @@ def extract_data_from_gamestate(self, dependencies): ): if not isinstance(raw_leader_dict, dict): continue - if raw_leader_dict.get("class") != "envoy": + if raw_leader_dict.get("class") not in {"envoy", "official"}: continue if envoy_id_ingame not in leaders: continue @@ -3099,6 +3160,12 @@ def extract_data_from_gamestate(self, dependencies): def _previous_assignment( self, envoy: datamodel.Leader ) -> Optional[datamodel.HistoricalEvent]: + # officials now do some assignments (galcom, federation) that envoys did previously + # however, the previous assignment logic breaks when officials then do other things + # for now, disabling this logic for non-envoys + # long term, all the leader processing should be refactored to address tech debt for special ruler/envoy logic + if envoy.leader_class != "envoy": + return None return ( self._session.query(datamodel.HistoricalEvent) .filter(datamodel.HistoricalEvent.end_date_days.is_(None))