SP Info AI Analysis of the strategic AI 1.153

Users who are viewing this thread

So, this is actually happening. We shall see how far it would go.

Goals:
  • enumeration of all MS-based semantic units of relevance
    • Def.: A "semantic unit" be one entry in a module file.
  • call graph for all elements of the enumeration
  • documentation per complex SU about internal behaviour
    • Def.: an SU be complex if it is not variable nor constant.
      • Approx.: If it takes more than one line, it be complex.
    • esp. enumeration of functional blocks (where applicable)
      • Def.: a "functional block" transform a set of parameters into a set of causal effects which is disjunct with these of all other functional blocks within an SU.
    • collateral effects

Everyone is welcome to participate.
Just mind to, when posting several complex semantic unit at once, keep them within separate spoiler-tags.
... Disregard that one, nested spoiler-tags do not work. Apply common sense as to how many fit into one post before it grew too congested.

semantic units listed:
 
Code:
war        (faction1, faction2) := relation       (faction1, faction2) < 0
truce      (faction1, faction2) := faction1.truce_slot      (faction2) > 0
casus_belli(faction1, faction2) := faction1.provocation_slot(faction2) > 0
strength   (faction)            := sum(value(faction.parties))
                                   +2 if faction is target and "fac_player_faction"
value      (party)              :=  3 if town,
                                    2 if castle or AI lord,
                                    1 if village,
                                    0 else
Concepts:
  • Relation - value in [-100, 100]
    • for a lord's view of another lord
    • for a faction's view of another faction
  • Controversy - value in [0, 100] for a lord's history of destabilising its own faction
    • Generation:
      • When relation between two lords of the same faction change by less than -5, both gain the inverse of the relation change as controversy.
 
script_randomly_start_war_peace_new

Invoked by:
  • script_game_start
  • 24h simple trigger at line 636
Invokes:Constants in use:
  • kingdoms_begin
  • kingdoms_end
  • slot_faction_state
    • sfs_active
  • slot_faction_war_damage_inflicted_on_factions_begin
Globals in use:
  • $g_include_diplo_explanation
    • get
    • set
Other resources in use:
  • reg0
    • get
  • s57
    • set
  • mnu_question_peace_offer
  • str_s14

Code:
  #script_randomly_start_war_peace_new
  # Input : arg0 = initializing_war_peace_cond (1 = true, 0 = false)
  # Output: none
  # Aims to introduce a slightly simpler system in which the AI kings' reasoning could be made more
  # transparent to the player. At the start of the game, this may lead to less variation in outcomes, though.
  ("randomly_start_war_peace_new",[
    (store_script_param_1, ":initializing_war_peace_cond"),

    (try_for_range, ":cur_kingdom", "fac_kingdom_1", kingdoms_end),
      (faction_slot_eq, ":cur_kingdom", slot_faction_state, sfs_active),
        (try_for_range, ":cur_kingdom_2", kingdoms_begin, kingdoms_end),
          (neq, ":cur_kingdom", ":cur_kingdom_2"),
          (faction_slot_eq, ":cur_kingdom_2", slot_faction_state, sfs_active),
            (call_script, "script_npc_decision_checklist_peace_or_war", ":cur_kingdom", ":cur_kingdom_2", -1),
            (assign, ":kingdom_1_to_kingdom_2", reg0),
            (store_relation, ":cur_relation", ":cur_kingdom", ":cur_kingdom_2"),
            (try_begin),
              (lt, ":cur_relation", 0), #AT WAR
              (ge, ":kingdom_1_to_kingdom_2", 1),
                (try_begin),
                  (eq, ":cur_kingdom_2", "fac_player_supporters_faction"),
                    (store_mul, ":goodwill_level", ":kingdom_1_to_kingdom_2", 2),
                    (store_random_in_range, ":random", 0, 20),
                    (lt, ":random", ":goodwill_level"),
                      (call_script, "script_add_notification_menu", "mnu_question_peace_offer", ":cur_kingdom", 0),
                (else_try),
                  (call_script, "script_npc_decision_checklist_peace_or_war", ":cur_kingdom_2", ":cur_kingdom", -1),
                  (assign, ":kingdom_2_to_kingdom_1", reg0),
                  (ge, ":kingdom_2_to_kingdom_1", 1),
                    (store_mul, ":goodwill_level", ":kingdom_1_to_kingdom_2", ":kingdom_2_to_kingdom_1"),
                    (store_random_in_range, ":random", 0, 20),
                    (lt, ":random", ":goodwill_level"),
                      (try_begin), # <= Investigate whether script_diplomacy_start_peace_between_kingdoms can lead to employ of g_include_diplo_explanation or s57!
                        (eq, "$g_include_diplo_explanation", 0),
                          (assign, "$g_include_diplo_explanation", ":cur_kingdom"),
                          (str_store_string, s57, "str_s14"),
                      (try_end),
                      (call_script, "script_diplomacy_start_peace_between_kingdoms", ":cur_kingdom", ":cur_kingdom_2", ":initializing_war_peace_cond"),
                (try_end),
            (else_try),
              (call_script, "script_npc_decision_checklist_peace_or_war", ":cur_kingdom", ":cur_kingdom_2", -1),
              #negative, leans towards war/positive, leans towards peace
              (le, reg0, 0), #still no chance of war unless provocation, or at start of game
                (assign, ":hostility", reg0),
                (call_script, "script_diplomacy_faction_get_diplomatic_status_with_faction", ":cur_kingdom", ":cur_kingdom_2"),
                (le, reg0, 0), #no truce
                  (val_add, ":hostility", reg0), #increase hostility if there is a provocation
                  (val_sub, ":hostility", 1), #greater chance at start of game
                  (val_add, ":hostility", ":initializing_war_peace_cond"), #this variable = 1 after the start
                  (val_mul, ":hostility", ":hostility"), # pow(hostility, 2)
                  (store_random_in_range, ":random", 0, 50),
                  (lt, ":random", ":hostility"),
                    (try_begin),
                      (eq, "$g_include_diplo_explanation", 0),
                        (assign, "$g_include_diplo_explanation", ":cur_kingdom"),
                        (str_store_string, s57, "str_s14"),
                    (try_end),	
                    (call_script, "script_diplomacy_start_war_between_kingdoms", ":cur_kingdom", ":cur_kingdom_2", ":initializing_war_peace_cond"),
                    #do some war damage for 
                    (eq, ":initializing_war_peace_cond", 0),
                      (store_random_in_range, ":war_damage_inflicted", 10, 120),
                      (store_add, ":slot_war_damage_inflicted", ":cur_kingdom", slot_faction_war_damage_inflicted_on_factions_begin),
                      (val_sub, ":slot_war_damage_inflicted", kingdoms_begin),
                      (faction_set_slot, ":cur_kingdom_2",  ":slot_war_damage_inflicted", ":war_damage_inflicted"),
                      (store_add, ":slot_war_damage_inflicted", ":cur_kingdom_2", slot_faction_war_damage_inflicted_on_factions_begin),
                      (val_sub, ":slot_war_damage_inflicted", kingdoms_begin),
                      (faction_set_slot, ":cur_kingdom", ":slot_war_damage_inflicted", ":war_damage_inflicted"),
            (try_end),
        (try_end),
    (try_end)
  ]),
Notes:
  • Investigate whether script_diplomacy_start_peace_between_kingdoms can lead to employ of g_include_diplo_explanation or s57!
 
script_diplomacy_start_peace_between_kingdoms

Invoked by:
  • dialog at line 4764
  • dialog at line 4814
  • dialog at line 10491
  • dialog at line 10565
  • menu_question_peace_offer
    • mno_peace_offer_accept
  • script_randomly_start_war_peace_new
  • 72h simple trigger at line 3514
Invokes:
  • script_exchange_prisoners_between_factions
  • script_set_player_relation_with_faction
  • script_event_kingdom_make_peace_with_kingdom
  • script_lift_siege
  • script_add_notification_menu
Constants in use:
  • centers_begin
  • centers_end
  • kingdoms_begin
  • slot_center_is_besieged_by
  • slot_faction_truce_days_with_factions_begin
  • slot_faction_war_damage_inflicted_on_factions_begin
Globals in use:
  • players_kingdom
    • get
  • g_player_besiege_town
    • get
  • g_recalculate_ais
    • set
Other resources in use:
  • s1
    • set
  • s2
    • set
  • mnu_notification_peace_declared

Code:
  #script_diplomacy_start_peace_between_kingdoms
  # Input : arg0 = kingdom1, arg1 = kingdom2, arg2 = initializing_war_peace_cond
  # Output: none
  # Sets relations between two kingdoms.
  ("diplomacy_start_peace_between_kingdoms",[
    (store_script_param_1, ":kingdom_a"),
    (store_script_param_2, ":kingdom_b"),
    (store_script_param, ":initializing_war_peace_cond", 3), #set to 1 if not the start of the game

    (store_relation, ":relation", ":kingdom_a", ":kingdom_b"),
    (val_max, ":relation", 0), # <= Investigate whether relation can actually be >0 on call!
    (set_relation, ":kingdom_a", ":kingdom_b", ":relation"),
    (call_script, "script_exchange_prisoners_between_factions", ":kingdom_a", ":kingdom_b"),
    # special treatment for kingdom with player <= Investigate whether fac_player_supporters_faction can be non-empty when players_kingdom != fac_player_supporters_faction!
    (try_begin),
      (eq, "$players_kingdom", ":kingdom_a"),
        (store_relation, ":relation", "fac_player_supporters_faction", ":kingdom_b"),
        (val_max, ":relation", 0),
        (call_script, "script_set_player_relation_with_faction", ":kingdom_b", ":relation"),
        (call_script, "script_event_kingdom_make_peace_with_kingdom", ":kingdom_b", "fac_player_supporters_faction"), #event cancels certain quests
    (else_try),
      (eq, "$players_kingdom", ":kingdom_b"),
        (store_relation, ":relation", "fac_player_supporters_faction", ":kingdom_a"),
        (val_max, ":relation", 0),
        (call_script, "script_set_player_relation_with_faction", ":kingdom_a", ":relation"),
        (call_script, "script_event_kingdom_make_peace_with_kingdom", ":kingdom_a", "fac_player_supporters_faction"), #event cancels certain quests
    (try_end),
    # aborts sieges in progress
    (try_for_range, ":cur_center", centers_begin, centers_end), # <= Investigate whether non-walled_centers actually are of interest!
      (store_faction_of_party, ":faction_no", ":cur_center"),
      (this_or_next|eq, ":faction_no", ":kingdom_a"),
      (eq, ":faction_no", ":kingdom_b"),
        (party_get_slot, ":besieger_party", ":cur_center", slot_center_is_besieged_by),
        (ge, ":besieger_party", 0), #town under siege
        (party_is_active, ":besieger_party"), # <= Investigate whether besieger can be inactive!
          (store_faction_of_party, ":besieger_party_faction_no", ":besieger_party"),
          (this_or_next|eq, ":besieger_party_faction_no", ":kingdom_a"),
          (eq, ":besieger_party_faction_no", ":kingdom_b"),
            (call_script, "script_lift_siege", ":cur_center", 0),
    (try_end),
    # special treatment for siege led by player
    (try_begin),
      (this_or_next|eq, "$players_kingdom", ":kingdom_a"),
      (eq, "$players_kingdom", ":kingdom_b"),
      (is_between, "$g_player_besiege_town", centers_begin, centers_end),
        (store_faction_of_party, ":besieged_center_faction_no", "$g_player_besiege_town"),
        (this_or_next|eq, ":besieged_center_faction_no", ":kingdom_a"),
        (eq, ":besieged_center_faction_no", ":kingdom_b"),
          (call_script, "script_lift_siege", "$g_player_besiege_town", 0),
          (assign, "$g_player_besiege_town", -1),
    (try_end),
    # send peace message and cancel war related quests
    (try_begin),
      (eq, ":initializing_war_peace_cond", 1),
        (str_store_faction_name_link, s1, ":kingdom_a"),
        (str_store_faction_name_link, s2, ":kingdom_b"),
        (display_log_message, "@{s1} and {s2} have made peace with each other."),
        (call_script, "script_add_notification_menu", "mnu_notification_peace_declared", ":kingdom_a", ":kingdom_b"), #stability penalty for early peace is in the menu
        (call_script, "script_event_kingdom_make_peace_with_kingdom", ":kingdom_a", ":kingdom_b"), #cancels quests
        (call_script, "script_event_kingdom_make_peace_with_kingdom", ":kingdom_b", ":kingdom_a"), #cancels quests
        (assign, "$g_recalculate_ais", 1),
    (try_end),
    # add truce
    (store_add, ":truce_slot", ":kingdom_a", slot_faction_truce_days_with_factions_begin),
    (val_sub, ":truce_slot", kingdoms_begin),
    (faction_set_slot, ":kingdom_b", ":truce_slot", 40),
    (store_add, ":truce_slot", ":kingdom_b", slot_faction_truce_days_with_factions_begin),
    (val_sub, ":truce_slot", kingdoms_begin),
    (faction_set_slot, ":kingdom_a", ":truce_slot", 40),
    (store_add, ":slot_war_damage_inflicted_on_b", ":kingdom_b", slot_faction_war_damage_inflicted_on_factions_begin),
    (val_sub, ":slot_war_damage_inflicted_on_b", kingdoms_begin),
    (faction_set_slot, ":kingdom_a", ":slot_war_damage_inflicted_on_b", 0),
    (store_add, ":slot_war_damage_inflicted_on_a", ":kingdom_a", slot_faction_war_damage_inflicted_on_factions_begin),
    (val_sub, ":slot_war_damage_inflicted_on_a", kingdoms_begin),
    (faction_set_slot, ":kingdom_b", ":slot_war_damage_inflicted_on_a", 0),
  ]),
Notes:
  • Investigate whether non-walled_centers actually are of interest!
  • Investigate whether besieger can be inactive!
  • Investigate whether relation can actually be >0 on call!
  • Investigate whether fac_player_supporters_faction can be non-empty when players_kingdom != fac_player_supporters_faction!
 
script_diplomacy_start_war_between_kingdoms

Invoked by:Invokes:Constants in use:
  • logent_player_faction_declares_war
  • logent_player_faction_declares_war
  • logent_faction_declares_war_out_of_personal_enmity
  • logent_faction_declares_war_to_regain_territory
  • logent_faction_declares_war_to_respond_to_provocation
  • logent_faction_declares_war_to_curb_power
  • logent_policy_ruler_declares_war_with_justification
  • logent_policy_ruler_attacks_without_provocation
  • logent_policy_ruler_breaks_truce
  • slot_faction_ai_last_decisive_event
  • slot_faction_truce_days_with_factions_begin
  • slot_faction_provocation_days_with_factions_begin
  • kingdoms_begin
Globals in use:
  • players_kingdom
    • get
  • g_recalculate_ais
    • set
Other resources in use:
  • fac_player_supporters_faction
  • str_s12s15_declared_war_to_control_calradia
  • str_s12s15_considers_s16_to_be_dangerous_and_untrustworthy_and_shehe_wants_to_bring_s16_down
  • str_s12s15_is_anxious_to_reclaim_old_lands_such_as_s18_now_held_by_s16
  • str_s12s15_faces_too_much_internal_discontent_to_feel_comfortable_ignoring_recent_provocations_by_s16s_subjects
  • str_s12s15_is_alarmed_by_the_growing_power_of_s16
  • s1
    • set
  • s2
    • set
  • reg0
    • get
  • reg1
    • get
  • qst_cause_provocation
  • mnu_notification_war_declared

Code:
  #script_diplomacy_start_war_between_kingdoms
  # Input : arg0 = kingdom1, arg1 = kingdom2, arg2 = initializing_war_peace_cond
  # Output: none
  # Sets relations between two kingdoms and their vassals.
  ("diplomacy_start_war_between_kingdoms",[
    (store_script_param, ":kingdom_a", 1),
    (store_script_param, ":kingdom_b", 2),
    (store_script_param, ":initializing_war_peace_cond", 3), # 1 = after start of game

    (call_script, "script_npc_decision_checklist_peace_or_war", ":kingdom_a", ":kingdom_b", -1),
    (assign, ":explainer_string", reg1),
    # pick appropriate log entry
    (try_begin),
      (eq, ":kingdom_a", "fac_player_supporters_faction"),
        (assign, ":war_event", logent_player_faction_declares_war),
    (else_try),
      (eq, ":explainer_string", "str_s12s15_declared_war_to_control_calradia"),
        (assign, ":war_event", logent_player_faction_declares_war), #for savegame compatibility, this event stands in for the attempt to declare war on all of calradia
    (else_try),
      (eq, ":explainer_string", "str_s12s15_considers_s16_to_be_dangerous_and_untrustworthy_and_shehe_wants_to_bring_s16_down"),
        (assign, ":war_event", logent_faction_declares_war_out_of_personal_enmity),
    (else_try),
      (eq, ":explainer_string", "str_s12s15_is_anxious_to_reclaim_old_lands_such_as_s18_now_held_by_s16"),
        (assign, ":war_event", logent_faction_declares_war_to_regain_territory),
    (else_try),
      (eq, ":explainer_string", "str_s12s15_faces_too_much_internal_discontent_to_feel_comfortable_ignoring_recent_provocations_by_s16s_subjects"),
        (assign, ":war_event", logent_faction_declares_war_to_respond_to_provocation),
    (else_try),
      (eq, ":explainer_string", "str_s12s15_is_alarmed_by_the_growing_power_of_s16"),
        (assign, ":war_event", logent_faction_declares_war_to_curb_power),
    (try_end),
    (call_script, "script_add_log_entry", ":war_event", ":kingdom_a", 0, 0, ":kingdom_b"),
    # check for and apply effect of political reception
    (call_script, "script_diplomacy_faction_get_diplomatic_status_with_faction", ":kingdom_a", ":kingdom_b"),
    (assign, ":current_diplomatic_status", reg0), # <= Investigate whether current_diplomatic_status can ever be -2 (atWar)!
    (try_begin), #effects of policy only after the start of the game
      (eq, ":initializing_war_peace_cond", 1),
      (eq, ":current_diplomatic_status", -1), # casus belli
        (call_script, "script_faction_follows_controversial_policy", ":kingdom_a", logent_policy_ruler_declares_war_with_justification),
    (else_try),
      (eq, ":initializing_war_peace_cond", 1),
      (eq, ":current_diplomatic_status", 0), # peace
        (call_script, "script_faction_follows_controversial_policy", ":kingdom_a", logent_policy_ruler_attacks_without_provocation),
    (else_try), # only one valid before game start
      (eq, ":current_diplomatic_status", 1), # truce
        (call_script, "script_faction_follows_controversial_policy", ":kingdom_a", logent_policy_ruler_breaks_truce),
    (try_end),
    # set new relation between warring factions
    (store_relation, ":relation", ":kingdom_a", ":kingdom_b"), # <= Investigate whether relation can be negative!
    (val_min, ":relation", -10),
    (val_add, ":relation", -30),
    (set_relation, ":kingdom_a", ":kingdom_b", ":relation"),
    # special treatment for player owned kingdom
    (try_begin),
      (eq, "$players_kingdom", ":kingdom_a"),
        (store_relation, ":relation", "fac_player_supporters_faction", ":kingdom_b"),
        (val_min, ":relation", -30),
        (call_script, "script_set_player_relation_with_faction", ":kingdom_b", ":relation"),
    (else_try),
      (eq, "$players_kingdom", ":kingdom_b"),
        (store_relation, ":relation", "fac_player_supporters_faction", ":kingdom_a"),
        (val_min, ":relation", -30),
        (call_script, "script_set_player_relation_with_faction", ":kingdom_a", ":relation"),
    (try_end),
    # construct war description strings
    (try_begin),
      (eq, ":initializing_war_peace_cond", 1),
        (str_store_faction_name_link, s1, ":kingdom_a"),
        (str_store_faction_name_link, s2, ":kingdom_b"),
        (display_log_message, "@{s1} has declared war against {s2}."),
        # register declaration of war as decisive event
        (store_current_hours, ":hours"),
        (faction_set_slot, ":kingdom_a", slot_faction_ai_last_decisive_event, ":hours"),
        (faction_set_slot, ":kingdom_b", slot_faction_ai_last_decisive_event, ":hours"),
        # reset provocation and truce days to 0
        (store_add, ":truce_slot", ":kingdom_b", slot_faction_truce_days_with_factions_begin),
        (store_add, ":provocation_slot", ":kingdom_b", slot_faction_provocation_days_with_factions_begin),
        (val_sub, ":truce_slot", kingdoms_begin),
        (val_sub, ":provocation_slot", kingdoms_begin),
        (faction_set_slot, ":kingdom_a", ":truce_slot", 0),
        (faction_set_slot, ":kingdom_a", ":provocation_slot", 0),
        (store_add, ":truce_slot", ":kingdom_a", slot_faction_truce_days_with_factions_begin),
        (store_add, ":provocation_slot", ":kingdom_a", slot_faction_provocation_days_with_factions_begin),
        (val_sub, ":truce_slot", kingdoms_begin),
        (val_sub, ":provocation_slot", kingdoms_begin),
        (faction_set_slot, ":kingdom_b", ":truce_slot", 0),
        (faction_set_slot, ":kingdom_b", ":provocation_slot", 0),
        # send notification to player and update faction notes
        (call_script, "script_add_notification_menu", "mnu_notification_war_declared", ":kingdom_a", ":kingdom_b"),
        (call_script, "script_update_faction_notes", ":kingdom_a"),
        (call_script, "script_update_faction_notes", ":kingdom_b"),
        (assign, "$g_recalculate_ais", 1),
    (try_end),
    # abort player quest to provoke a war between kingdom_a and kingdom_b
    (try_begin),
      (check_quest_active, "qst_cause_provocation"),
      (neg|check_quest_succeeded, "qst_cause_provocation"),
      (this_or_next|eq, "$players_kingdom", ":kingdom_a"),
      (eq, "$players_kingdom", ":kingdom_b"),
        (call_script, "script_abort_quest", "qst_cause_provocation", 0),
    (try_end),
  ]),
Notes:
  • Investigate whether current_diplomatic_status can ever be -2 (atWar)!
  • Investigate whether relation can be negative!
 
script_diplomacy_faction_get_diplomatic_status_with_faction

Output:
  • reg0 in [-2, 1] - current state of relations
    • -2 - war
    • -1 - kingdom1 has casus belli against kingdom2
      • reg1 is valid
    • 0 - peace
    • 1 - truce
      • reg1 is valid
  • reg1 - days until state obsolesces
    • for truce in [0, 40]
    • for CB in [0, 30]

Invoked by:Invokes:
  • nothing
Constants in use:
  • slot_faction_truce_days_with_factions_begin
  • slot_faction_provocation_days_with_factions_begin
  • kingdoms_begin
Globals in use:
  • none
Other resources in use:
  • reg0
    • set
  • reg1
    • set

Code:
  #script_diplomacy_faction_get_diplomatic_status_with_faction
  # INPUT : arg0 = kingdom1, arg1 = kingdom2
  # OUTPUT: reg0 = result, reg1 = time before result obsolesces
  # possible results:
  # -2 - war
  # -1 - kingdom1 has casus belli against kingdom2 - timed
  #  1 - truce                                     - timed
  #  0 - peace
  ("diplomacy_faction_get_diplomatic_status_with_faction",[
    (store_script_param, ":actor_faction", 1),
    (store_script_param, ":target_faction", 2),

    # initialise variables
    (store_add, ":truce_slot", ":target_faction", slot_faction_truce_days_with_factions_begin),
    (store_add, ":provocation_slot", ":target_faction", slot_faction_provocation_days_with_factions_begin),
    (val_sub, ":truce_slot", kingdoms_begin),
    (val_sub, ":provocation_slot", kingdoms_begin),
    (assign, ":result", 0),
    (assign, ":duration", 0),
    # calculate result
    (try_begin),
      (store_relation, ":relation", ":actor_faction", ":target_faction"),
      (lt, ":relation", 0),
        (assign, ":result", -2),
    (else_try),
      (faction_slot_ge, ":actor_faction", ":truce_slot", 1),
        (assign, ":result", 1),
        (faction_get_slot, ":duration", ":actor_faction", ":truce_slot"),
    (else_try),
      (faction_slot_ge, ":actor_faction", ":provocation_slot", 1),
        (assign, ":result", -1),
        (faction_get_slot, ":duration", ":actor_faction", ":provocation_slot"),
    (try_end),
    # set return values
    (assign, reg0, ":result"),
    (assign, reg1, ":duration"),
	]),
Notes:
  • none
 
script_npc_decision_checklist_peace_or_war

Output:
  • reg0 in [-3 , 3] - desire to war/ally
    • positive: befriend
    • negative: antagonise
    • distance from 0 denotes intensity

Invoked by:Invokes:Constants in use:
  • slot_faction_leader
  • slot_faction_war_damage_inflicted_on_factions_begin
  • kingdoms_begin
  • kingdoms_end
  • active_npcs_begin
  • active_npcs_end
  • towns_begin
  • towns_end
  • castles_begin
  • castles_end
  • villages_begin
  • villages_end
  • walled_centers_begin
  • walled_centers_end
  • slot_faction_temp_slot
  • slot_center_original_faction
  • slot_center_ex_faction
  • slot_faction_state
    • sfs_active
  • slot_faction_ai_last_decisive_event
  • slot_faction_ai_state
    • sfai_attacking_center
    • sfai_raiding_village
    • sfai_attacking_enemy_army
  • slot_faction_ai_object
Globals in use:
  • player_honor
    • get
  • g_talk_troop
    • get
  • supported_pretender
    • get
  • supported_pretender_old_faction
    • get
Other resources in use:
  • reg0
    • get
  • reg4
    • set
  • s12
    • set
  • s14
    • set
  • s15
    • set
  • s16
    • set
  • s17
    • set
  • s18
    • set
  • fac_player_supporters_faction
  • skl_persuasion
  • str_s15_is_at_war_with_s16_
  • str_in_the_short_term_s15_has_a_truce_with_s16_as_a_matter_of_general_policy_
  • str_in_the_short_term_s15_was_recently_provoked_by_s16_and_is_under_pressure_to_declare_war_as_a_matter_of_general_policy_
  • str_s12s15_cannot_negotiate_with_s16_as_to_do_so_would_undermine_reg4herhis_own_claim_to_the_throne_this_civil_war_must_almost_certainly_end_with_the_defeat_of_one_side_or_another
  • str_s12s15_considers_s16_to_be_dangerous_and_untrustworthy_and_shehe_wants_to_bring_s16_down
  • str_s12s15_is_anxious_to_reclaim_old_lands_such_as_s18_now_held_by_s16
  • str_s12s15_feels_that_reg4shehe_is_winning_the_war_against_s16_and_sees_no_reason_not_to_continue
  • str_s12s15_faces_too_much_internal_discontent_to_feel_comfortable_ignoring_recent_provocations_by_s16s_subjects
  • str_s12even_though_reg4shehe_is_fighting_on_two_fronts_s15_is_inclined_to_continue_the_war_against_s16_for_a_little_while_longer_for_the_sake_of_honor
  • str_s12s15_feels_that_reg4shehe_must_pursue_the_war_against_s16_for_a_little_while_longer_for_the_sake_of_honor
  • str_s12s15_is_currently_on_the_offensive_against_s17_now_held_by_s16_and_reluctant_to_negotiate
  • str_s12s15_is_alarmed_by_the_growing_power_of_s16
  • str_s12s15_declared_war_to_control_calradia
  • str_s12s15_distrusts_s16_and_fears_that_any_deals_struck_between_the_two_realms_will_not_be_kept
  • str_s12s15_is_at_war_on_too_many_fronts_and_eager_to_make_peace_with_s16
  • str_s12s15_seems_to_think_that_s16_and_reg4shehe_have_a_common_enemy_in_the_s17
  • str_s12s15_feels_frustrated_by_reg4herhis_inability_to_strike_a_decisive_blow_against_s16
  • str_s12s15_would_like_to_firm_up_a_truce_with_s16_to_respond_to_the_threat_from_the_s17
  • str_s12s15_wishes_to_be_at_peace_with_s16_so_as_to_pursue_the_war_against_the_s17
  • str_s12s15_seems_to_be_intimidated_by_s16_and_would_like_to_avoid_hostilities
  • str_s12s15_has_no_particular_reason_to_continue_the_war_with_s16_and_would_probably_make_peace_if_given_the_opportunity
  • str_s12s15_seems_to_be_willing_to_improve_relations_with_s16

Code:
  #script_npc_decision_checklist_peace_or_war
  # INPUT : arg0 = kingdom1, arg1 = kingdom2, arg2 = envoy troop
  # OUTPUT: reg0 = result, reg1 = explanation_string, s14 = explanation_string
  # This script is used to add a bit more color to diplomacy, particularly with regards to the player.
  ("npc_decision_checklist_peace_or_war",[
    (store_script_param, ":actor_faction", 1),
    (store_script_param, ":target_faction", 2),
    (store_script_param, ":envoy", 3),

    (assign, ":actor_strength", 0),
    (assign, ":target_strength", 0),
    (assign, ":actor_centers_held_by_target", 0),
    (assign, ":third_party_war", 0),
    (assign, ":num_third_party_wars", 0),
    (assign, ":active_mutual_enemy", 0), # an active enemy with which the target is at war

    (try_begin),
      (eq, ":target_faction", "fac_player_supporters_faction"),
        (assign, ":modified_honor_and_relation", "$player_honor"), #this can be affected by the emissary's skill
        (val_add, ":target_strength", 2), #for player party
    (else_try),
      (assign, ":modified_honor_and_relation", 0), #this can be affected by the emissary's skill
    (try_end),

    (faction_get_slot, ":actor_leader", ":actor_faction", slot_faction_leader),
    (faction_get_slot, ":target_leader", ":target_faction", slot_faction_leader),
    (call_script, "script_troop_get_relation_with_troop", ":actor_leader", ":target_leader"),
    (assign, ":relation_bonus", reg0),
    (val_min, ":relation_bonus", 10),
    (val_add, ":modified_honor_and_relation", ":relation_bonus"),

    (str_store_troop_name, s15, ":actor_leader"),
    (str_store_troop_name, s16, ":target_leader"),

    (assign, ":war_damage_suffered", 0),
    (assign, ":war_damage_inflicted", 0),

    (call_script, "script_diplomacy_faction_get_diplomatic_status_with_faction", ":actor_faction", ":target_faction"),
    (assign, ":war_peace_truce_status", reg0),
    (str_clear, s12),
    (try_begin),
      (eq, ":war_peace_truce_status", -2), # at war
        (str_store_string, s12, "str_s15_is_at_war_with_s16_"),
        (store_add, ":war_damage_inflicted_slot", ":target_faction", slot_faction_war_damage_inflicted_on_factions_begin),
        (val_sub, ":war_damage_inflicted_slot", kingdoms_begin),
        (faction_get_slot, ":war_damage_inflicted", ":actor_faction", ":war_damage_inflicted_slot"),
        (store_add, ":war_damage_suffered_slot", ":actor_faction", slot_faction_war_damage_inflicted_on_factions_begin),
        (val_sub, ":war_damage_suffered_slot", kingdoms_begin),
        (faction_get_slot, ":war_damage_suffered", ":target_faction", ":war_damage_suffered_slot"),
    (else_try),
      (eq, ":war_peace_truce_status", 1), # truce in effect
        (str_store_string, s12, "str_in_the_short_term_s15_has_a_truce_with_s16_as_a_matter_of_general_policy_"),
    (else_try),
      (eq, ":war_peace_truce_status", -1), # provocation noted
        (str_store_string, s12, "str_in_the_short_term_s15_was_recently_provoked_by_s16_and_is_under_pressure_to_declare_war_as_a_matter_of_general_policy_"),
    (try_end),
    # clear for dialog with lords
    (try_begin),
      (is_between, "$g_talk_troop", active_npcs_begin, active_npcs_end),
        (str_clear, s12),
    (try_end),

    (try_begin),
      (gt, ":envoy", -1),
        (store_skill_level, ":persuasion_x_2", "skl_persuasion", ":envoy"),
        (val_mul, ":persuasion_x_2", 2),
        (val_add, ":modified_honor_and_relation", ":persuasion_x_2"),
      (try_end),
    # clear the temp slot of all kingdoms
    (try_for_range, ":kingdom_to_reset", kingdoms_begin, kingdoms_end),
      (faction_set_slot, ":kingdom_to_reset", slot_faction_temp_slot, 0),
    (try_end),

    (try_for_parties, ":party_no"),
      # store strength impact of party by type
      (try_begin),
        (is_between, ":party_no", towns_begin, towns_end),
          (assign, ":party_value", 3),
      (else_try),	
        (is_between, ":party_no", castles_begin, castles_end),
          (assign, ":party_value", 2),
      (else_try),
        (is_between, ":party_no", villages_begin, villages_end),
          (assign, ":party_value", 1),
      (else_try),	
        (party_get_template_id, ":template", ":party_no"),
        (eq, ":template", "pt_kingdom_hero_party"),
          (assign, ":party_value", 2),
      (else_try),
        (assign, ":party_value", 0),
      (try_end),
      # store current and last owner
      (store_faction_of_party, ":party_current_faction", ":party_no"),
      (party_get_slot, ":party_original_faction", ":party_no", slot_center_original_faction),
      (party_get_slot, ":party_ex_faction", ":party_no", slot_center_ex_faction),
      # calculate total strength in temp slot
      (try_begin),
        (is_between, ":party_current_faction", kingdoms_begin, kingdoms_end),
          (faction_get_slot, ":faction_strength", ":party_current_faction", slot_faction_temp_slot),
          (val_add, ":faction_strength", ":party_value"),
          (faction_set_slot, ":party_current_faction", slot_faction_temp_slot, ":faction_strength"),
      (try_end),
      # accumulate actor and target strength
      (try_begin),
        (eq, ":party_current_faction", ":target_faction"),
          (val_add, ":target_strength", ":party_value"),
          (this_or_next|eq, ":party_original_faction", ":actor_faction"),
          (eq, ":party_ex_faction", ":actor_faction"),
            # count centers originally or last held by actor and now held by target
            (val_add, ":actor_centers_held_by_target", 1),
            # add as war goal the last (by ID) of the walled centers among these
            (is_between, ":party_no", walled_centers_begin, walled_centers_end),
              (str_store_party_name, s18, ":party_no"),
      (else_try),
        (eq, ":party_current_faction", ":actor_faction"),
          (val_add, ":actor_strength", ":party_value"),
      (try_end),
    (try_end),
    # Total Calradia strength = 110 x 1 (villages,), 48? x 2 castles, 22 x 3 towns, 88 x 2 lord parties = 272 + 176 = 448
    (assign, ":strongest_kingdom", -1),
    (assign, ":score_to_beat", 60), # below this, the strongest kingdom is not of interest
    (try_for_range, ":strongest_kingdom_candidate", kingdoms_begin, kingdoms_end),
      (faction_get_slot, ":candidate_strength", ":strongest_kingdom_candidate", slot_faction_temp_slot),
      (gt, ":candidate_strength", ":score_to_beat"),
        (assign, ":strongest_kingdom", ":strongest_kingdom_candidate"),
        (assign, ":score_to_beat", ":candidate_strength"),
    (try_end),
    # compute relative strength between actor and target
    (try_begin),
      (gt, ":actor_strength", 0),
        (store_mul, ":strength_ratio", ":target_strength", 100),
        (val_div, ":strength_ratio", ":actor_strength"),
    (else_try), # <= Investigate whether faction with 0 strength can actually be actor_target!
      (assign, ":strength_ratio", 1),
    (try_end),
    # look up mutual enemies
    (try_for_range, ":possible_mutual_enemy", kingdoms_begin, kingdoms_end),
      (neq, ":possible_mutual_enemy", ":target_faction"),
      (neq, ":possible_mutual_enemy", ":actor_faction"),
      (faction_slot_eq, ":possible_mutual_enemy", slot_faction_state, sfs_active),
        (store_relation, ":relation", ":possible_mutual_enemy", ":actor_faction"),
        (lt, ":relation", 0),
          (assign, ":third_party_war", ":possible_mutual_enemy"),
          (val_add, ":num_third_party_wars", 1),
          (store_relation, ":relation", ":possible_mutual_enemy", ":target_faction"),
          (lt, ":relation", 0),
            (assign, ":active_mutual_enemy", ":possible_mutual_enemy"),
    (try_end),
    # fetch time since last decisive AI event
    (store_current_hours, ":cur_hours"),
    (faction_get_slot, ":faction_ai_last_decisive_event", ":actor_faction", slot_faction_ai_last_decisive_event),
    (store_sub, ":hours_since_last_decisive_event", ":cur_hours", ":faction_ai_last_decisive_event"),
    # decide peace or war
    (try_begin),
      (gt, "$supported_pretender", 0),
      (this_or_next|eq, "$supported_pretender", ":actor_leader"),
      (eq, "$supported_pretender", ":target_leader"),
      (this_or_next|eq, ":actor_faction", "$supported_pretender_old_faction"),
      (eq, ":target_faction", "$supported_pretender_old_faction"),
        (assign, ":result", -3),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":explainer_string", "str_s12s15_cannot_negotiate_with_s16_as_to_do_so_would_undermine_reg4herhis_own_claim_to_the_throne_this_civil_war_must_almost_certainly_end_with_the_defeat_of_one_side_or_another"),
    (else_try),
      (lt, ":modified_honor_and_relation", -20),
      (lt, ":strength_ratio", 125),
      (lt, ":war_damage_suffered", 400),
      (this_or_next|neq, ":war_peace_truce_status", -2),
      (lt, ":hours_since_last_decisive_event", 720),
      (eq, ":num_third_party_wars", 0),
        (assign, ":result", -3),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":explainer_string", "str_s12s15_considers_s16_to_be_dangerous_and_untrustworthy_and_shehe_wants_to_bring_s16_down"),
    (else_try),
      (gt, ":actor_centers_held_by_target", 0),
      (lt, ":war_damage_suffered", 200),
      (lt, ":strength_ratio", 125),
      (eq, ":num_third_party_wars", 0),
        (assign, ":result", -2),
        (assign, ":explainer_string", "str_s12s15_is_anxious_to_reclaim_old_lands_such_as_s18_now_held_by_s16"),
    (else_try),
      (eq, ":war_peace_truce_status", -2),
      (lt, ":strength_ratio", 125),
      (le, ":num_third_party_wars", 1),
      (ge, ":war_damage_inflicted", 5),
      (this_or_next|neq, ":war_peace_truce_status", -2),
      (lt, ":hours_since_last_decisive_event", 720),
        (store_mul, ":war_damage_suffered_x_2", ":war_damage_suffered", 2),
        (gt, ":war_damage_inflicted", ":war_damage_suffered_x_2"),
          (assign, ":result", -2),
          (troop_get_type, reg4, ":actor_leader"),
          (assign, ":explainer_string", "str_s12s15_feels_that_reg4shehe_is_winning_the_war_against_s16_and_sees_no_reason_not_to_continue"),
    (else_try),
      (le, ":war_peace_truce_status", -1),
      (le, ":war_damage_inflicted", 1), # either a war is just beginning, or there is a provocation
      (lt, ":strength_ratio", 150),
      (eq, ":num_third_party_wars", 0),
      (faction_slot_ge, ":actor_faction", slot_faction_instability, 60),
        (assign, ":result", -1),
        (assign, ":explainer_string", "str_s12s15_faces_too_much_internal_discontent_to_feel_comfortable_ignoring_recent_provocations_by_s16s_subjects"),
    (else_try),
      (eq, ":war_peace_truce_status", -2),
      (lt, ":war_damage_inflicted", 100),
      (eq, ":num_third_party_wars", 1),
        (assign, ":result", -1),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":explainer_string", "str_s12even_though_reg4shehe_is_fighting_on_two_fronts_s15_is_inclined_to_continue_the_war_against_s16_for_a_little_while_longer_for_the_sake_of_honor"),
    (else_try),
      (eq, ":war_peace_truce_status", -2),
      (lt, ":war_damage_inflicted", 100),
      (eq, ":num_third_party_wars", 0),
        (assign, ":result", -1),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":explainer_string", "str_s12s15_feels_that_reg4shehe_must_pursue_the_war_against_s16_for_a_little_while_longer_for_the_sake_of_honor"),
    (else_try),
      (this_or_next|faction_slot_eq, ":actor_faction", slot_faction_ai_state, sfai_attacking_center),
      (this_or_next|faction_slot_eq, ":actor_faction", slot_faction_ai_state, sfai_raiding_village),
      (faction_slot_eq, ":actor_faction", slot_faction_ai_state, sfai_attacking_enemy_army),
        (faction_get_slot, ":offensive_object", ":actor_faction", slot_faction_ai_object),
        (party_is_active, ":offensive_object"),
          (store_faction_of_party, ":offensive_object_faction", ":offensive_object"),
          (eq, ":offensive_object_faction", ":target_faction"),
            (str_store_party_name, s17, ":offensive_object"),
            (assign, ":result", -1),
            (assign, ":explainer_string", "str_s12s15_is_currently_on_the_offensive_against_s17_now_held_by_s16_and_reluctant_to_negotiate"),
    (else_try),
      # Attack strongest kingdom, if it is also at war
      (eq, ":strongest_kingdom", ":target_faction"),
      (eq, ":num_third_party_wars", 0),
      (this_or_next|ge, ":war_peace_truce_status", -1), # not at war or at war for less than two months
      (lt, ":hours_since_last_decisive_event", 1440), # <= Investigate whether another decisive event besides declaration of war may have occured!
        (assign, ":at_least_one_other_faction_at_war_with_strongest", 0),
        (try_for_range, ":kingdom_to_check", kingdoms_begin, kingdoms_end),
          (neq, ":kingdom_to_check", ":actor_faction"),
          (neq, ":kingdom_to_check", ":target_faction"),
          (faction_slot_eq, ":kingdom_to_check", slot_faction_state, sfs_active),
            (store_relation, ":relation_of_factions", ":kingdom_to_check", ":target_faction"),
            (lt, ":relation_of_factions", 0),
              (assign, ":at_least_one_other_faction_at_war_with_strongest", 1),
        (try_end),
        (eq, ":at_least_one_other_faction_at_war_with_strongest", 1),
          (assign, ":result", -1),
          (assign, ":explainer_string", "str_s12s15_is_alarmed_by_the_growing_power_of_s16"),
    (else_try),
      # bid to conquer all Calradia
      (eq, ":num_third_party_wars", 0),
      (eq, ":actor_faction", ":strongest_kingdom"),
        # peace with no truce or provocation
        (faction_get_slot, ":target_strength", ":target_faction", slot_faction_temp_slot), # removes player +2 for target_faction == fac_player_faction
        (store_sub, ":strength_difference", ":actor_strength", ":target_strength"),
        (ge, ":strength_difference", 30),
          (assign, ":nearby_center_found", 0),
          (try_for_range, ":actor_faction_walled_center", walled_centers_begin, walled_centers_end),
            (store_faction_of_party, ":walled_center_faction_1", ":actor_faction_walled_center"),
            (eq, ":walled_center_faction_1", ":actor_faction"),
              (try_for_range, ":target_faction_walled_center", walled_centers_begin, walled_centers_end),
                (store_faction_of_party, ":walled_center_faction_2", ":target_faction_walled_center"),
                (eq, ":walled_center_faction_2", ":target_faction"),
                  (store_distance_to_party_from_party, ":distance", ":target_faction_walled_center", ":actor_faction_walled_center"),
                  (lt, ":distance", 25),
                    (assign, ":nearby_center_found", 1),
              (try_end),
          (try_end),
          (eq, ":nearby_center_found", 1),
            (assign, ":result", -1),
            (assign, ":explainer_string", "str_s12s15_declared_war_to_control_calradia"),
    (else_try),
      (lt, ":modified_honor_and_relation", -20),
        (assign, ":result", 0),
        (assign, ":explainer_string", "str_s12s15_distrusts_s16_and_fears_that_any_deals_struck_between_the_two_realms_will_not_be_kept"),
    # wishes to deal
    (else_try),
        (eq, ":war_peace_truce_status", -2), # at war
        (ge, ":num_third_party_wars", 2),
          (assign, ":result", 3),
          (assign, ":explainer_string", "str_s12s15_is_at_war_on_too_many_fronts_and_eager_to_make_peace_with_s16"),
    (else_try),
      (gt, ":active_mutual_enemy", 0),
      (eq, ":actor_centers_held_by_target", 0),
        (assign, ":result", 3),
        (str_store_faction_name, s17, ":active_mutual_enemy"),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":explainer_string", "str_s12s15_seems_to_think_that_s16_and_reg4shehe_have_a_common_enemy_in_the_s17"),
    (else_try),
      (eq, ":war_peace_truce_status", -2),
      (ge, ":hours_since_last_decisive_event", 720),
        (troop_get_type, reg4, ":actor_leader"),
        (assign, ":result", 2),
        (assign, ":explainer_string", "str_s12s15_feels_frustrated_by_reg4herhis_inability_to_strike_a_decisive_blow_against_s16"),
    (else_try),
      (gt, ":third_party_war", 0),
      (ge, ":modified_honor_and_relation", 0),
        (assign, ":result", 1),
        (str_store_faction_name, s17, ":third_party_war"),
        (try_begin),
          (eq, ":war_peace_truce_status", -2), # at war
          (assign, ":explainer_string", "str_s12s15_would_like_to_firm_up_a_truce_with_s16_to_respond_to_the_threat_from_the_s17"),
        (else_try),
          (assign, ":explainer_string", "str_s12s15_wishes_to_be_at_peace_with_s16_so_as_to_pursue_the_war_against_the_s17"),
        (try_end),
    (else_try),
      (gt, ":strength_ratio", 175),
        (assign, ":result", 1),
        (assign, ":explainer_string", "str_s12s15_seems_to_be_intimidated_by_s16_and_would_like_to_avoid_hostilities"),
    (else_try),
      (eq, ":war_peace_truce_status", -2), # at war
        (assign, ":result", 1),
        (assign, ":explainer_string", "str_s12s15_has_no_particular_reason_to_continue_the_war_with_s16_and_would_probably_make_peace_if_given_the_opportunity"),
    (else_try),
      (assign, ":result", 1),
      (assign, ":explainer_string", "str_s12s15_seems_to_be_willing_to_improve_relations_with_s16"),
    (try_end),

    (str_store_string, s14, ":explainer_string"),
    (assign, reg0, ":result"),
    (assign, reg1, ":explainer_string"), # <= Investigate whether explainer_string is really necessary in both reg1 and s14!
  ]),
... This one is... special. If you account for this hellish contraption, make sure never to mention it in approximate striking distance of any software engineer.
Oh, and mayhap you want to learn Malbolge? It would suit you.

Notes:
  • Investigate whether faction with 0 strength can actually be actor_target!
  • Investigate whether explainer_string is really necessary in both reg1 and s14!
  • Investigate whether another decisive event besides declaration of war may have occured!
 
Haha, you're actually going for it, and documenting the results!  :grin:  Rock on, man, this is precisely the stuff we need somebody to get done to make progress. 

I totally agree with your analysis of script_npc_decision_checklist_peace_or_war btw  :lol:

This has already been pretty useful to me, in terms of looking at what I have half-heartedly wanted to mess with for some time now; getting rid of most of the Lord control system and replacing it with a simpler, cleaner strategic overlay.  I could care less about simulating Lord / Lord intrigues, Marshal voting or the rest of that stuff; I want to get rid of it all and write a simple strategic AI that will actually fight wars in a non-retarded fashion.

Man, this makes me want to try and bite the bullet and just rewrite this sucker from the ground up, with a different approach and a lot more simplicity... like, IDK, just setting everything up for peace / war at the start and let it play itself out over the course of a game, not write the code to purposefully create near-stasis.
 
I have got an important question and would like answer from at least a couple of people:
What to do with obvious bugs!?
Basically, when cleaning a script, I have cancelled down complicated values.
In a situation like this:
Code:
    (else_try),
      (lt, ":current_faction_relation", 0), # at war
      (gt, ":war_damage_suffered", 100),
        # In this script, war_damage_suffered_x_2 has only been used in ANOTHER else_try of the same try_begin so far.
        # This is enough to silence the compiler, but of course different else_tries on this level can NEVER be entered consecutively.
        (val_mul, ":war_damage_suffered_x_2", 2), # FRESHLY INITIALISED - IS 0!!!
        (lt, ":war_damage_inflicted", ":war_damage_suffered_x_2"), # ALWAYS WRONG - war_damage_inflicted is at least 0!
          (assign, ":result", 2),
          (assign, ":explainer_string", "str_s12s15_has_suffered_enough_in_the_war_with_s16_for_too_little_gain_and_is_ready_to_pursue_a_peace"),
The result would be:
Code:
<nothing>
This would of course demonstrate exactly the vanilla behaviour. However, the - probably - intended behaviour would be:
Code:
    (else_try),
      (eq, ":war_peace_truce_status", -2), # at war
      (gt, ":war_damage_suffered", 100),
        (store_mul, ":war_damage_suffered_x_2", ":war_damage_suffered", 2),
        (lt, ":war_damage_inflicted", ":war_damage_suffered_x_2"), # unless more than twice as much has been inflicted
          (assign, ":result", 2),
          (assign, ":explainer_string", "str_s12s15_has_suffered_enough_in_the_war_with_s16_for_too_little_gain_and_is_ready_to_pursue_a_peace"),
Of course, no one knows, whether this "correct" code would actually work better.

I am therefore more inclined to strictly keep to the current behaviour, be it as faulty as it may.
 
I would only replace the val_mul line with:
(store_mul, ":war_damage_suffered_x_2", ":war_damage_suffered", 2),

You don't mess with ":war_damage_suffered" since it has a script-wide use - you are not supposed to change it, even if no code block actually uses it till the end of the script. It's also more readable this way.

A good catch. Quickly to the bugtracker, before they release 1.155.
 
You are right. Corrected. Also, added as 4098 into the bugtracker.

Another one:
Code:
      # bid to conquer all Calradia
      (eq, ":num_third_party_wars", 0),
      (eq, ":actor_faction", ":strongest_kingdom"),
        # peace with no truce or provocation
        (faction_get_slot, ":actor_strength", ":actor_faction", slot_faction_temp_slot),
        (faction_get_slot, ":target_strength", ":target_faction", slot_faction_temp_slot),
        (store_sub, ":strength_difference", ":actor_strength", ":target_strength"),
        (ge, ":strength_difference", 30),
          (assign, ":nearby_center_found", 0),
          (try_for_range, ":actor_faction_walled_center", walled_centers_begin, walled_centers_end),
            (store_faction_of_party, ":walled_center_faction_1", ":actor_faction_walled_center"),
            (eq, ":walled_center_faction_1", ":actor_faction"),
              (try_for_range, ":target_faction_walled_center", walled_centers_begin, walled_centers_end),
                (store_faction_of_party, ":walled_center_faction_2", ":target_faction_walled_center"),
                (eq, ":walled_center_faction_2", ":target_faction"),
                  (store_distance_to_party_from_party, ":distance", ":target_faction_walled_center", ":actor_faction_walled_center"),
                  (lt, ":distance", 25),
                    (assign, ":nearby_center_found", 1),
              (try_end),
          (try_end),
          (eq, ":nearby_center_found", 1),
            (assign, ":result", -1),
            (assign, ":explainer_string", "str_s12s15_declared_war_to_control_calradia"),
This one refreshes actor_strength and target_strength, although they have not been touched before. For actor_strength, this will result in nothing, for target_strength, the +2 fac_player_faction gets for the player (who is no AI lord and thus does not provide the common 2 strength to any faction) is flushed due to the way the faction's slot was filled:
Code:
    (try_for_parties, ":party_no"),
      # store strength impact of party by type
      (try_begin),
        (is_between, ":party_no", towns_begin, towns_end),
          (assign, ":party_value", 3),
      (else_try),	
        (is_between, ":party_no", castles_begin, castles_end),
          (assign, ":party_value", 2),
      (else_try),
        (is_between, ":party_no", villages_begin, villages_end),
          (assign, ":party_value", 1),
      (else_try),	
        (party_get_template_id, ":template", ":party_no"),
        (eq, ":template", "pt_kingdom_hero_party"),
          (assign, ":party_value", 2),
      (else_try),
        (assign, ":party_value", 0),
      (try_end),
      # store current and last owner
      (store_faction_of_party, ":party_current_faction", ":party_no"),
      (party_get_slot, ":party_original_faction", ":party_no", slot_center_original_faction),
      (party_get_slot, ":party_ex_faction", ":party_no", slot_center_ex_faction),
      # calculate total strength in temp slot
      (try_begin),
        (is_between, ":party_current_faction", kingdoms_begin, kingdoms_end),
          (faction_get_slot, ":faction_strength", ":party_current_faction", slot_faction_temp_slot),
          (val_add, ":faction_strength", ":party_value"), # PARTY VALUE IS ADDED TO THE SLOT WHICH DOES NOT CONTAIN THE PLAYER'S +2
          (faction_set_slot, ":party_current_faction", slot_faction_temp_slot, ":faction_strength"),
      (try_end),
      # accumulate actor and target strength
      (try_begin),
        (eq, ":party_current_faction", ":target_faction"),
          (val_add, ":target_strength", ":party_value"),  # PARTY VALUE IS ADDED TO target_strength,
                                                          # WHICH (if applicable) DOES CONTAIN THE PLAYER'S +2
          (this_or_next|eq, ":party_original_faction", ":actor_faction"),
          (eq, ":party_ex_faction", ":actor_faction"),
            # count centers originally or last held by actor and now held by target
            (val_add, ":actor_centers_held_by_target", 1),
            # add as war goal the last (by ID) of the walled centers among these
            (is_between, ":party_no", walled_centers_begin, walled_centers_end),
              (assign, "$g_concession_demanded", ":party_no"),
              (str_store_party_name, s18, "$g_concession_demanded"),
      (else_try),
        (eq, ":party_current_faction", ":actor_faction"),
          (val_add, ":actor_strength", ":party_value"),
      (try_end),
    (try_end),
So for this block, target_strength is by 2 smaller than for all other blocks if fac_player_faction is the target.

The consistent way to calculate this would be to fill the slots first, then add the player +2 if applicable and then set the actor_strength and target_strength variables once.
... This might as well be deliberate, though:
  • Unless every else_try had been written by a different person and this block done by the local clueless one, it quite cannot be an oversight.
  • The actor_strength does not factor in the player at all.
  • The target_strength does not factor in the player, if another faction than fac_player_faction is the target.
    • So any AI kingdom containing the player is in fact one lord short in these calculations.
 
script_faction_follows_controversial_policy

Invoked by:Invokes:Constants in use:
  • active_npcs_begin
  • active_npcs_end
  • slot_faction_leader
  • slot_troop_occupation
    • slto_kingdom_hero
  • slot_lord_reputation_type
    • lrep_martial
    • lrep_quarrelsome
    • lrep_selfrighteous
    • lrep_debauched
    • lrep_goodnatured
    • lrep_benefactor
    • lrep_custodian
    • lrep_upstanding
  • logent_policy_ruler_attacks_without_provocation
  • logent_policy_ruler_ignores_provocation
  • logent_policy_ruler_declares_war_with_justification
  • logent_policy_ruler_breaks_truce
  • logent_policy_ruler_makes_peace_too_soon
Globals in use:
  • total_policy_dispute_changes
    • set
Other resources in use:
  • trp_player

Code:
  #script_faction_follows_controversial_policy
  # INPUT : arg0 = faction, arg1 = policy_kind
  # OUTPUT: none
  ("faction_follows_controversial_policy",[
    (store_script_param, ":faction_no", 1),
    (store_script_param, ":policy_type", 2),

    (faction_get_slot, ":faction_leader", ":faction_no", slot_faction_leader),
    # set honour change and relation effect by policy_type
    (try_begin),
      (eq, ":policy_type", logent_policy_ruler_attacks_without_provocation),
        (assign, ":hawk_relation_effect", 0),
        (assign, ":honorable_relation_effect", -2),
        (assign, ":honor_change", -1),
    (else_try),
      (eq, ":policy_type", logent_policy_ruler_ignores_provocation),
        (assign, ":hawk_relation_effect", -3),
        (assign, ":honorable_relation_effect", 0),
        (assign, ":honor_change", 0),
    (else_try),
      (eq, ":policy_type", logent_policy_ruler_declares_war_with_justification),
        (assign, ":hawk_relation_effect", 3),
        (assign, ":honorable_relation_effect", 1),
        (assign, ":honor_change", 0),
    (else_try),
      (eq, ":policy_type", logent_policy_ruler_breaks_truce),
        (assign, ":hawk_relation_effect", 0),
        (assign, ":honorable_relation_effect", -3),
        (assign, ":honor_change", -5),
    (else_try),
      (eq, ":policy_type", logent_policy_ruler_makes_peace_too_soon),
        (assign, ":hawk_relation_effect", -5),
        (assign, ":honorable_relation_effect", 0),
        (assign, ":honor_change", 0),
    (try_end),
    # apply honour change to player
    (try_begin),
      (eq, ":faction_leader", "trp_player"),
        (call_script, "script_change_player_honor", ":honor_change"),
    (try_end),
    # apply relation effects on faction members
    (try_for_range, ":lord", active_npcs_begin, active_npcs_end),
      (troop_slot_eq, ":lord", slot_troop_occupation, slto_kingdom_hero),
        (store_faction_of_troop, ":lord_faction", ":lord"),
        (eq, ":lord_faction", ":faction_no"),
        (neq, ":lord", ":faction_leader"),
          # apply affect for pro-war lords
          (try_begin),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_martial),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_quarrelsome),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_selfrighteous),
            (troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_debauched),
              (call_script, "script_troop_change_relation_with_troop", ":faction_leader", ":lord", ":hawk_relation_effect"),
              (val_add, "$total_policy_dispute_changes", ":hawk_relation_effect"),
          (try_end),
          # apply effect for honourable lords
          (try_begin),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_martial),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_goodnatured),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_selfrighteous),
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_benefactor), #new for enfiefed commoners
            (this_or_next|troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_custodian), #new for enfiefed commoners
            (troop_slot_eq, ":lord", slot_lord_reputation_type, lrep_upstanding),
              (call_script, "script_troop_change_relation_with_troop", ":faction_leader", ":lord", ":honorable_relation_effect"),
              (val_add, "$total_policy_dispute_changes", ":honorable_relation_effect"),
          (try_end),
    (try_end)
  ]),
Notes:
  • none
 
script_troop_change_relation_with_troop

Invoked by:
  • 59 times in module_dialogs.py
  • menu_faction_orders
    • mno_faction_orders_political_collapse
  • menu_notification_faction_defeated
    • mno_continue
  • script_game_start
  • script_game_event_simulate_battle
  • script_change_troop_faction
  • script_give_center_to_lord
  • script_village_set_state
  • script_process_village_raids
  • script_check_and_finish_active_army_quests_for_faction
  • script_abort_quest
  • script_cf_random_political_event
  • script_battle_political_consequences
  • script_appoint_faction_marshall
  • script_faction_conclude_feast
  • script_courtship_event_troop_court_lady
  • script_courtship_event_bride_marry_groom
  • script_faction_follows_controversial_policy
  • script_indict_lord_for_treason
  • 1/2h simple_trigger at 953
Invokes:
  • script_change_player_relation_with_troop
  • script_troop_get_relation_with_troop
Constants in use:
  • kingdoms_begin
  • kingdoms_end
  • slot_troop_relations_begin
  • slot_troop_controversy
Globals in use:
  • players_kingdom
    • get
Other resources in use:
  • reg0
    • get
  • trp_player

Code:
  #script_troop_change_relation_with_troop
  # INPUT : arg0 = troop1, arg1 = troop2, arg2 = value
  # OUTPUT: none
  ("troop_change_relation_with_troop",[
    (store_script_param_1, ":troop1"),
    (store_script_param_2, ":troop2"),
    (store_script_param, ":amount", 3),

    (try_begin),
      (eq, ":troop1", "trp_player"),
        (call_script, "script_change_player_relation_with_troop", ":troop2", ":amount"),
    (else_try),
      (eq, ":troop2", "trp_player"),
        (call_script, "script_change_player_relation_with_troop", ":troop1", ":amount"),
    (else_try),
      (eq, ":troop1", ":troop2"),
    (else_try),
      (call_script, "script_troop_get_relation_with_troop", ":troop1", ":troop2"),
      (store_add, ":new_relation", reg0, ":amount"),
      (val_clamp, ":new_relation", -100, 101),
      (try_begin),
        (eq, ":new_relation", 0),
          (assign, ":new_relation", 1), # this removes the need for a separate "met" slot - any non-zero relation will be a met
      (try_end),
      (store_add, ":troop1_slot_for_troop2", ":troop2", slot_troop_relations_begin), # worst hack ever seen: slot_troop_relations_begin is 0
      (troop_set_slot, ":troop1", ":troop1_slot_for_troop2", ":new_relation"),
      (store_add, ":troop2_slot_for_troop1", ":troop1", slot_troop_relations_begin),
      (troop_set_slot, ":troop2", ":troop2_slot_for_troop1", ":new_relation"),
    (try_end),
    # generate controversy for quarrellers in the same faction
    (try_begin),
      (lt, ":amount", -5),
        # fetch factions of troops
        (try_begin),
          (eq, ":troop1", "trp_player"),
            (assign, ":faction1", "$players_kingdom"),
        (else_try),
          (store_faction_of_troop, ":faction1", ":troop1"),
        (try_end),
        (try_begin),
          (eq, ":troop2", "trp_player"),
            (assign, ":faction2", "$players_kingdom"),
        (else_try),	
          (store_faction_of_troop, ":faction2", ":troop2"),
        (try_end),
        (eq, ":faction1", ":faction2"),
        (is_between, ":faction1", kingdoms_begin, kingdoms_end),
          (store_mul, ":controversy_generated", ":amount", -1),
          # add controversy to both
          (troop_get_slot, ":controversy1", ":troop1", slot_troop_controversy),
          (val_add, ":controversy1", ":controversy_generated"),
          (val_min, ":controversy1", 100),
          (troop_set_slot, ":troop1", slot_troop_controversy, ":controversy1"),
          (troop_get_slot, ":controversy2", ":troop2", slot_troop_controversy),
          (val_add, ":controversy2", ":controversy_generated"),
          (val_min, ":controversy2", 100),
          (troop_set_slot, ":troop2", slot_troop_controversy, ":controversy2"),
    (try_end)
  ]),
Notes:
  • none
 
script_cf_random_political_event

Invoked by:
  • script_game_start
  • 8h simple_trigger at line 940
Invokes:
  • script_troop_get_relation_with_troop
  • script_troop_change_relation_with_troop
  • script_add_notification_menu
  • script_add_log_entry
  • script_cf_test_lord_incompatibility_to_s17
  • script_cf_troop_can_intrigue
  • script_calculate_troop_political_factors_for_liege
Constants in use:
  • active_npcs_begin
  • active_npcs_end
  • companions_begin
  • companions_end
  • kingdoms_begin
  • kingdoms_end
  • slot_troop_occupation
    • slto_kingdom_hero
  • slot_troop_personalityclash_object
  • slot_troop_personalityclash2_object
  • slot_faction_leader
  • slot_quest_object_troop
  • slot_quest_target_troop
  • logent_ruler_intervenes_in_quarrel
Globals in use:
  • g_minister_notification_quest
    • get
    • set
Other resources in use:
  • reg0
    • get
  • trp_player
  • qst_consult_with_minister
  • qst_resolve_dispute
  • mnu_notification_player_should_consult

Code:
  #script_cf_random_political_event
  # INPUT : none
  # OUTPUT: none
  # FAIL  : arbitrarily
  # right now, just enmities
  ("cf_random_political_event",[
    # fetch two random lords
    (store_random_in_range, ":lord_1", active_npcs_begin, active_npcs_end),
    (store_random_in_range, ":lord_2", active_npcs_begin, active_npcs_end),
    (troop_slot_eq, ":lord_1", slot_troop_occupation, slto_kingdom_hero),
    (troop_slot_eq, ":lord_2", slot_troop_occupation, slto_kingdom_hero),
    # ensure they be not equal
    (neq, ":lord_1", ":lord_2"),
      (store_troop_faction, ":lord_1_faction", ":lord_1"),
      (store_troop_faction, ":lord_2_faction", ":lord_2"),
      (faction_get_slot, ":faction_1_leader", ":lord_1_faction", slot_faction_leader),
      (faction_get_slot, ":faction_2_leader", ":lord_2_faction", slot_faction_leader),
      # ensure one of them be faction leader or both share one faction
      (this_or_next|eq, ":lord_1_faction", ":lord_2_faction"),
      (this_or_next|eq, ":lord_1", ":faction_1_leader"),
      (eq, ":lord_2", ":faction_2_leader"),
        (call_script, "script_troop_get_relation_with_troop", ":lord_1", ":lord_2"),
        (assign, ":relation", reg0),
        (store_random_in_range, ":random", 0, 100),
        (try_begin),
          # reconciliation - AI leader only
          # The chance of a liege reconciling two quarreling vassals is equal to (relationship with lord 1 x relationship with lord 2) / 4.
          (eq, ":lord_1_faction", ":lord_2_faction"),
          (neq, ":faction_1_leader", "trp_player"),
          (le, ":relation", -10),
            (call_script, "script_troop_get_relation_with_troop", ":lord_1", ":faction_1_leader"),
            (gt, reg0, 0),
              (assign, ":lord_1_leader_rel", reg0),
              (call_script, "script_troop_get_relation_with_troop", ":lord_2", ":faction_1_leader"),
              (gt, reg0, 0),
                (store_mul, ":reconciliation_chance", ":lord_1_leader_rel", reg0),
                (val_div, ":reconciliation_chance", 4),
                (le, ":random", ":reconciliation_chance"),
                  (call_script, "script_troop_change_relation_with_troop", ":lord_1", ":lord_2", 20),
        (else_try),
          # leader intervention
          (eq, ":lord_1_faction", ":lord_2_faction"),
          (le, ":relation", -10),
            (try_begin),
              (eq, ":faction_1_leader", "trp_player"),
              (neg|check_quest_active, "qst_consult_with_minister"),
              (neg|check_quest_active, "qst_resolve_dispute"),
              (eq, "$g_minister_notification_quest", 0),
                (assign, "$g_minister_notification_quest", "qst_resolve_dispute"),
                (quest_set_slot, "qst_resolve_dispute", slot_quest_target_troop, ":lord_1"),
                (quest_set_slot, "qst_resolve_dispute", slot_quest_object_troop, ":lord_2"),
                (call_script, "script_add_notification_menu", "mnu_notification_player_should_consult", 0, 0),
            (else_try),
              # for AI leader, lord with better relation to leader wins
              (call_script, "script_troop_get_relation_with_troop", ":lord_1", ":faction_1_leader"),
              (assign, ":lord_1_rel_w_leader", reg0),
              (call_script, "script_troop_get_relation_with_troop", ":lord_2", ":faction_1_leader"),
              (assign, ":lord_2_rel_w_leader", reg0),
              (store_random_in_range, ":another_random", -5, 5), # noise - outcome less clear the closer relations to leader are to neutral 0
              (val_add, ":lord_1_rel_w_leader", ":another_random"),
              # set winner and loser after noise has been applied
              (try_begin),
                (ge, ":lord_1_rel_w_leader", ":lord_2_rel_w_leader"),
                  (assign, ":winner_lord", ":lord_1"),
                  (assign, ":loser_lord", ":lord_2"),
              (else_try),
                (assign, ":winner_lord", ":lord_2"),
                (assign, ":loser_lord", ":lord_1"),
              (try_end),
              (call_script, "script_add_log_entry", logent_ruler_intervenes_in_quarrel, # faction leader is actor, loser lord is center object
               ":faction_1_leader",  ":loser_lord", ":winner_lord", ":lord_1_faction"), # winner lord is troop_object
              # apply effect on relation to leader: winner likes, loser dislikes
              (call_script, "script_troop_change_relation_with_troop", ":winner_lord", ":faction_1_leader", 10),
              (call_script, "script_troop_change_relation_with_troop", ":loser_lord", ":faction_1_leader", -20),
            (try_end),
        (else_try),
          # new quarrel - companions
          (is_between, ":lord_1", companions_begin, companions_end),
          (is_between, ":lord_2", companions_begin, companions_end),
          (ge, ":relation", -10),
          (this_or_next|troop_slot_eq, ":lord_1", slot_troop_personalityclash_object, ":lord_2"), # one dislikes the personality of the other
          (troop_slot_eq, ":lord_1", slot_troop_personalityclash2_object, ":lord_2"),
            (call_script, "script_troop_change_relation_with_troop", ":lord_1", ":lord_2", -30),
        (else_try),
          # new quarrel - others
          (eq, ":lord_1_faction", ":lord_2_faction"),
          (ge, ":relation", -10), # can have two quarrels
            (call_script, "script_cf_test_lord_incompatibility_to_s17", ":lord_1", ":lord_2"),
            (assign, ":chance_of_enmity", reg0),
            (gt, ":chance_of_enmity", 0),
            (lt, ":random", ":chance_of_enmity"), # 50 or 100 percent, usually
              (call_script, "script_troop_change_relation_with_troop", ":lord_1", ":lord_2", -30),
        (else_try),
          # a lord attempts to suborn a character
          (store_current_hours, ":hours"), # not within the first game day
          (ge, ":hours", 24),
          (neq, ":lord_1_faction", ":lord_2_faction"),
          (is_between, ":lord_1_faction", kingdoms_begin, kingdoms_end),
          (call_script, "script_cf_troop_can_intrigue", ":lord_2", 0),
          (neq, ":lord_2", ":faction_2_leader"),
          (neq, ":lord_2", ":faction_1_leader"),
            (call_script, "script_calculate_troop_political_factors_for_liege", ":lord_2", ":faction_1_leader"),
            (assign, ":lord_1_score", reg0),
            (call_script, "script_calculate_troop_political_factors_for_liege", ":lord_2", ":faction_2_leader"),
            (assign, ":faction_2_leader_score", reg0),
            (try_begin),
              (gt, ":lord_1_score", ":faction_2_leader_score"),
                (call_script, "script_change_troop_faction", ":lord_2", ":lord_1_faction"),
            (try_end),
        (try_end)
  ]),
Notes:
  • none
 
I have a new nemesis. You thought "script_npc_decision_checklist_peace_or_war" was bad? Well, what about "script_calculate_troop_political_factors_for_liege"?
Look at this:
Code:
    # FACTOR 4 - IDEOLOGY
    # lord's calculation of ideological comfort
    (troop_get_slot, ":recruitment_argument", ":troop", slot_lord_recruitment_argument),
    (call_script, "script_rebellion_arguments", ":troop", ":recruitment_argument", ":liege"),
    (assign, ":argument_appeal", reg0),
    (assign, ":argument_strength", reg1),
    (store_add, ":result_for_argument", ":argument_appeal", ":argument_strength"),
    # player liege
    (store_skill_level, ":player_persuasion_skill", "skl_persuasion", "trp_player"),
    (try_begin),
      (gt, ":result_for_argument", 0), # <= Investigate whether 0-sum argument is strong enough to ensure that liege be player!
      #make sure player is the one making the overture
      
      #if player has 0 persuasion, ":result_for_argument" will be multiplied by 3/10.
      (store_add, ":player_persuasion_skill_plus_5_mul_066", ":player_persuasion_skill", 5),
      (val_mul, ":player_persuasion_skill_plus_5_mul_066", 2),
      (val_div, ":player_persuasion_skill_plus_5_mul_066", 3),
      (val_mul, ":result_for_argument", ":player_persuasion_skill_plus_5_mul_066"),
      (val_div, ":result_for_argument", 10),
    (else_try),
      (lt, ":result_for_argument", 0), # <= Investigate whether 0-sum argument is strong enough to ensure that liege be player!
      (store_sub, ":ten_minus_player_persuasion_skill", 10, ":player_persuasion_skill"),
      (val_mul, ":result_for_argument", ":ten_minus_player_persuasion_skill"),
      (val_div, ":result_for_argument", 10),
    (try_end),
    # ... so we have just assumed that result_for_argument be 0 where player not involved... OR we have applied player skill to an AI lord!!!
    (try_begin),
      (neq, ":liege", "trp_player"),
      (neq, ":liege", "$supported_pretender"), # player is advocate for pretender
        (val_div, ":argument_strength", 2),
        (val_div, ":argument_appeal", 2),
        (val_div, ":result_for_argument", 2),
    (try_end),
Some help would be really conductive.
"script_rebellion_arguments" does not in any way ensure that an AI liege's result_for_argument would automatically be 0.

addendum:
I have not abandoned this just yet. Merely need to finish my bachelor thesis within the week and it, one might write, "has priority" in a way.
 
Back
Top Bottom