Project Alice
Loading...
Searching...
No Matches
diplomatic_messages.cpp
Go to the documentation of this file.
2#include "system_state.hpp"
3#include "commands.hpp"
4#include "nations.hpp"
5#include "ai.hpp"
6
8
9void decline(sys::state& state, message const& m) {
10 switch(m.type) {
11 case type::none:
12 break;
14 if(!command::can_ask_for_access(state, m.from, m.to))
15 return;
16
17 nations::adjust_relationship(state, m.from, m.to, state.defines.askmilaccess_relation_on_decline);
18
20 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
21 text::add_line(state, contents, "msg_access_refused_1", text::variable_type::x, target, text::variable_type::y, source);
22 },
23 "msg_access_refused_title",
24 m.to, m.from, dcon::nation_id{},
26 });
27 break;
29 if(!command::can_ask_for_alliance(state, m.from, m.to))
30 return;
31
32 nations::adjust_relationship(state, m.from, m.to, state.defines.alliance_relation_on_decline);
33
35 [from = m.from, to = m.to](sys::state& state, text::layout_base& contents) {
36 text::add_line(state, contents, "msg_alliance_declined_1", text::variable_type::x, to, text::variable_type::y, from);
37 },
38 "msg_alliance_declined_title",
39 m.to, m.from, dcon::nation_id{},
41 });
42 break;
44 if(!command::can_call_to_arms(state, m.from, m.to, m.data.war))
45 return;
46
47 nations::adjust_relationship(state, m.from, m.to, state.defines.callally_relation_on_decline);
48 auto was_defensive = false;
49 for(auto wp : state.world.war_get_war_participant(m.data.war)) {
50 if(wp.get_nation() == m.from) {
51 was_defensive = !wp.get_is_attacker();
52 break;
53 }
54 }
55 if(was_defensive) {
56 auto rel = state.world.get_diplomatic_relation_by_diplomatic_pair(m.from, m.to);
57 if(rel && state.world.diplomatic_relation_get_are_allied(rel)) {
58 state.world.diplomatic_relation_set_are_allied(rel, false);
59
61 [from = m.from, to = m.to](sys::state& state, text::layout_base& contents) {
62 text::add_line(state, contents, "msg_alliance_ends_1", text::variable_type::x, to, text::variable_type::y, from);
63 },
64 "msg_alliance_ends_title",
65 m.to, m.from, dcon::nation_id{},
67 });
68 }
69 }
70
72 [from = m.from, to = m.to, pa = state.world.war_get_primary_attacker(m.data.war), pd = state.world.war_get_primary_defender(m.data.war), name = state.world.war_get_name(m.data.war), tag = state.world.war_get_over_tag(m.data.war), st = state.world.war_get_over_state(m.data.war)](sys::state& state, text::layout_base& contents) {
73 text::substitution_map sub;
74 text::add_to_substitution_map(sub, text::variable_type::order, std::string_view(""));
75 text::add_to_substitution_map(sub, text::variable_type::second, text::get_adjective(state, pd));
76 text::add_to_substitution_map(sub, text::variable_type::second_country, pd);
77 text::add_to_substitution_map(sub, text::variable_type::first, text::get_adjective(state, pa));
78 text::add_to_substitution_map(sub, text::variable_type::third, tag);
79 text::add_to_substitution_map(sub, text::variable_type::state, st);
80
81 std::string resolved_war_name = text::resolve_string_substitution(state, name, sub);
82 text::add_line(state, contents, "msg_ally_call_decline_1", text::variable_type::x, to, text::variable_type::y, from, text::variable_type::val, std::string_view{resolved_war_name});
83 },
84 "msg_ally_call_declined_title",
85 m.to, m.from, dcon::nation_id{},
87 });
88
89 break;
90 }
93 break;
96 break;
98 military::reject_peace_offer(state, m.data.peace);
99 break;
102 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
103 text::add_line(state, contents, "msg_crisis_joffer_reject_1", text::variable_type::x, target, text::variable_type::y, source);
104
105 },
106 "msg_crisis_joffer_rejected",
107 m.to, m.from, dcon::nation_id{},
109 });
110 break;
112 // TODO: notify rejected
113 /*
114 Crisis resolution offers function much in the same way as peace offers. Every refused crisis offer increases the temperature
115 of the current crisis by define:CRISIS_TEMPERATURE_ON_OFFER_DECLINE.
116 */
117 state.crisis_temperature += state.defines.crisis_temperature_on_offer_decline;
118 nations::cleanup_crisis_peace_offer(state, m.data.peace);
119
121 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
122 text::add_line(state, contents, "msg_crisis_not_settled_1", text::variable_type::x, target, text::variable_type::y, source);
123
124 },
125 "msg_crisis_not_settled_title",
126 m.to, m.from, dcon::nation_id{},
128 });
129
130 break;
132 break;
133 }
134}
135
136bool can_accept_crisis_offer(sys::state& state, dcon::nation_id from, dcon::nation_id to, sys::full_wg offer) {
137 if(state.current_crisis_state != sys::crisis_state::heating_up)
138 return false;
139 if(from != state.primary_crisis_attacker && from != state.primary_crisis_defender)
140 return false;
141
142 if(to == offer.target_nation || from == offer.target_nation)
143 return false;
144
145 // to must be merely interested participant
146 for(auto& par : state.crisis_participants) {
147 if(!par.id) {
148 return false; // not in crisis
149 }
150 if(par.id == to) {
151 if(par.merely_interested == false)
152 return false; // already in crisis
153 break;
154 }
155 }
156
157 // target must be in crisis
158 for(auto& par : state.crisis_participants) {
159 if(!par.id) {
160 return false; // not in crisis
161 }
162 if(par.id == offer.target_nation) {
163 if(par.merely_interested)
164 return false;
165 if(par.supports_attacker && from == state.primary_crisis_attacker)
166 return false;
167 if(!par.supports_attacker && from == state.primary_crisis_defender)
168 return false;
169
170 break;
171 }
172 }
173
174 auto cb_type = state.world.cb_type_get_type_bits(offer.cb);
175 if((cb_type & military::cb_flag::always) == 0 && (cb_type & military::cb_flag::is_not_constructing_cb) != 0)
176 return false;
177
178 if(!military::cb_instance_conditions_satisfied(state, to, offer.target_nation, offer.cb, offer.state,
179 offer.wg_tag, offer.secondary_nation)) {
180
181 return false;
182 }
183
184 return true;
185}
186
187void add_to_crisis_with_offer(sys::state& state, dcon::nation_id from, dcon::nation_id to, sys::full_wg offer) {
188
189 for(auto& par : state.crisis_participants) {
190 if(!par.id) {
191 return; // not in crisis
192 }
193 if(par.id == to) {
194 par.merely_interested = false;
195 par.supports_attacker = (from == state.primary_crisis_attacker);
196 if(par.supports_attacker) {
197 nations::crisis_add_wargoal(state.crisis_attacker_wargoals, offer);
198 }
199 else {
200 nations::crisis_add_wargoal(state.crisis_defender_wargoals, offer);
201 }
202 break;
203 }
204 }
205
206 auto infamy = military::crisis_cb_addition_infamy_cost(state, offer.cb, to, offer.target_nation, offer.state) *
207 state.defines.crisis_wargoal_infamy_mult;
208 state.world.nation_get_infamy(from) += infamy;
209}
210
211bool can_accept_crisis_peace_offer(sys::state& state, dcon::nation_id from, dcon::nation_id to, dcon::peace_offer_id peace) {
212 if(state.current_crisis_state != sys::crisis_state::heating_up)
213 return false;
214 if(from != state.primary_crisis_attacker && from != state.primary_crisis_defender)
215 return false;
216 if(to != state.primary_crisis_attacker && to != state.primary_crisis_defender)
217 return false;
218 if(from == to)
219 return false;
220
221 // check: all goals in offer are part of the crisis
222 for(auto wg : state.world.peace_offer_get_peace_offer_item(peace)) {
223 bool found = [&]() {
224 for(auto par : state.crisis_attacker_wargoals) {
225 if(par.added_by == wg.get_wargoal().get_added_by()) {
226 if(wg.get_wargoal().get_associated_state() == par.state &&
227 wg.get_wargoal().get_associated_tag() == par.wg_tag &&
228 wg.get_wargoal().get_secondary_nation() == par.secondary_nation &&
229 wg.get_wargoal().get_target_nation() == par.target_nation &&
230 wg.get_wargoal().get_type() == par.cb)
231 return true;
232 }
233 }
234 for(auto par : state.crisis_defender_wargoals) {
235 if(par.added_by == wg.get_wargoal().get_added_by()) {
236 if(wg.get_wargoal().get_associated_state() == par.state &&
237 wg.get_wargoal().get_associated_tag() == par.wg_tag &&
238 wg.get_wargoal().get_secondary_nation() == par.secondary_nation &&
239 wg.get_wargoal().get_target_nation() == par.target_nation &&
240 wg.get_wargoal().get_type() == par.cb)
241 return true;
242 }
243 }
244 return false;
245 }();
246
247 if(!found)
248 return false;
249 }
250
251 return true;
252}
253
254bool can_accept(sys::state& state, message const& m) {
255 switch(m.type) {
256 case type::none:
257 return true;
258 case type::access_request:
259 return command::can_ask_for_access(state, m.from, m.to, true);
260 case type::alliance_request:
261 return command::can_ask_for_alliance(state, m.from, m.to, true);
262 case type::call_ally_request:
263 return command::can_call_to_arms(state, m.from, m.to, m.data.war, true);
264 case type::be_crisis_primary_attacker:
265 case type::be_crisis_primary_defender:
266 case type::peace_offer:
267 return true;
268 case type::take_crisis_side_offer:
269 return can_accept_crisis_offer(state, m.from, m.to, m.data.crisis_offer);
270 case type::crisis_peace_offer:
271 return can_accept_crisis_peace_offer(state, m.from, m.to, m.data.peace);
272 case type::state_transfer:
273 return command::can_state_transfer(state, m.from, m.to, m.data.state);
274 }
275 return true;
276}
277
278void accept(sys::state& state, message const& m) {
279 if(!can_accept(state, m))
280 return;
281
282 switch(m.type) {
283 case type::none:
284 break;
285 case type::access_request: {
286 nations::adjust_relationship(state, m.from, m.to, state.defines.askmilaccess_relation_on_accept);
287 auto rel = state.world.get_unilateral_relationship_by_unilateral_pair(m.to, m.from);
288 if(!rel) {
289 rel = state.world.force_create_unilateral_relationship(m.to, m.from);
290 }
291 state.world.unilateral_relationship_set_military_access(rel, true);
292
294 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
295 text::add_line(state, contents, "msg_access_granted_1", text::variable_type::x, target, text::variable_type::y, source);
296 },
297 "msg_access_granted_title",
298 m.to, m.from, dcon::nation_id{},
300 });
301 break;
302 }
303 case type::alliance_request: {
304 nations::adjust_relationship(state, m.from, m.to, state.defines.alliance_relation_on_accept);
305 nations::make_alliance(state, m.from, m.to);
306 break;
307 }
308 case type::call_ally_request: {
309 military::add_to_war(state, m.data.war, m.to, military::is_attacker(state, m.data.war, m.from));
310 nations::adjust_relationship(state, m.from, m.to, state.defines.callally_relation_on_accept);
312 [from = m.from, to = m.to, pa = state.world.war_get_primary_attacker(m.data.war), pd = state.world.war_get_primary_defender(m.data.war), name = state.world.war_get_name(m.data.war), tag = state.world.war_get_over_tag(m.data.war), st = state.world.war_get_over_state(m.data.war)](sys::state& state, text::layout_base& contents) {
313 text::substitution_map sub;
314 text::add_to_substitution_map(sub, text::variable_type::order, std::string_view(""));
315 text::add_to_substitution_map(sub, text::variable_type::second, text::get_adjective(state, pd));
316 text::add_to_substitution_map(sub, text::variable_type::second_country, pd);
317 text::add_to_substitution_map(sub, text::variable_type::first, text::get_adjective(state, pa));
318 text::add_to_substitution_map(sub, text::variable_type::third, tag);
319 text::add_to_substitution_map(sub, text::variable_type::state, st);
320
321 std::string resolved_war_name = text::resolve_string_substitution(state, name, sub);
322 text::add_line(state, contents, "msg_ally_call_accepted_1", text::variable_type::x, to, text::variable_type::y, from, text::variable_type::val, std::string_view{resolved_war_name});
323 },
324 "msg_ally_call_accepted_title",
325 m.to, m.from, dcon::nation_id{},
327 });
328
329 break;
330 }
331 case type::be_crisis_primary_attacker:
333 break;
334 case type::be_crisis_primary_defender:
336 break;
337 case type::peace_offer:
338 military::implement_peace_offer(state, m.data.peace);
339 break;
340 case type::take_crisis_side_offer:
341 add_to_crisis_with_offer(state, m.from, m.to, m.data.crisis_offer);
343 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
344 text::add_line(state, contents, "msg_crisis_joffer_accepted_1", text::variable_type::x, target, text::variable_type::y, source);
345
346 },
347 "msg_crisis_joffer_accepted",
348 m.to, m.from, dcon::nation_id{},
350 });
351 break;
352 case type::crisis_peace_offer:
353 nations::accept_crisis_peace_offer(state, m.from, m.to, m.data.peace);
355 [source = m.from, target = m.to](sys::state& state, text::layout_base& contents) {
356 text::add_line(state, contents, "msg_crisis_settled_1", text::variable_type::x, target, text::variable_type::y, source);
357 },
358 "msg_crisis_settled_title",
359 m.to, m.from, dcon::nation_id{},
361 });
362 break;
363 case type::state_transfer:
364 for(const auto ab : state.world.state_definition_get_abstract_state_membership(m.data.state)) {
365 if(ab.get_province().get_province_ownership().get_nation() == m.from) {
366 province::change_province_owner(state, ab.get_province(), m.to);
367 }
368 }
372 break;
373 }
374}
375
382bool ai_will_accept(sys::state& state, message const& m) {
383 if(state.world.nation_get_is_player_controlled(m.from) && state.cheat_data.always_accept_deals)
384 return true;
385
386 switch(m.type) {
387 case type::none:
388 std::abort();
389 break;
390 case type::access_request:
391 return ai::ai_will_grant_access(state, m.to, m.from);
392 case type::alliance_request:
393 return ai::ai_will_accept_alliance(state, m.to, m.from);
394 case type::call_ally_request:
395 if(!command::can_call_to_arms(state, m.from, m.to, m.data.war, true))
396 return false;
397 return ai::will_join_war(state, m.to, m.data.war, military::get_role(state, m.data.war, m.from) == military::war_role::attacker);
398 case type::be_crisis_primary_defender:
399 return ai::will_be_crisis_primary_defender(state, m.to);
400 case type::be_crisis_primary_attacker:
401 return ai::will_be_crisis_primary_attacker(state, m.to);
402 case type::peace_offer:
403 return ai::will_accept_peace_offer(state, m.to, m.from, m.data.peace);
404 case type::take_crisis_side_offer:
405 return ai::will_join_crisis_with_offer(state, m.to, m.data.crisis_offer);
406 case type::crisis_peace_offer:
407 return ai::will_accept_crisis_peace_offer(state, m.to, m.data.peace);
408 case type::state_transfer:
409 auto rel = state.world.nation_get_overlord_as_subject(m.to);
410 auto overlord = state.world.overlord_get_ruler(rel);
411 if(overlord == m.from) {
412 return true; // Always accept overlord reorganizing states
413 }
414 static std::vector<dcon::state_instance_id> target_states;
415 ai::state_target_list(target_states, state, m.to, m.from);
416
417 for(auto sid : target_states) {
418 if(state.world.state_instance_get_definition(sid) == m.data.state) {
419 return true; // AI wants this state
420 }
421 }
422 return false;
423 }
424 return false;
425}
426
432void post(sys::state& state, message const& m) {
433 if(state.world.nation_get_is_player_controlled(m.to) == false) {
434 if(ai_will_accept(state, m)) {
435 accept(state, m);
436 } else {
437 decline(state, m);
438 }
439 return;
440 }
441
442 for(auto& i : state.pending_messages) {
443 if(i.type == type::none) {
444 std::memcpy(&i, &m, sizeof(message));
445 i.when = state.current_date;
446
447 if(i.to == state.local_player_nation) {
448 state.new_requests.push(i);
449 }
450
451 return;
452 }
453 }
454}
455
457 for(auto& m : state.pending_messages) {
458 if(m.type != type::none && m.when + expiration_in_days <= state.current_date) {
459
460 decline(state, m);
461 m.type = type::none;
462 }
463 }
464}
465
466} // namespace diplomatic_message
bool ai_will_accept_alliance(sys::state &state, dcon::nation_id target, dcon::nation_id from)
Definition: ai.cpp:283
bool will_accept_peace_offer(sys::state &state, dcon::nation_id n, dcon::nation_id from, dcon::peace_offer_id p)
Definition: ai.cpp:3531
void state_target_list(std::vector< dcon::state_instance_id > &result, sys::state &state, dcon::nation_id for_nation, dcon::nation_id within)
Definition: ai.cpp:2264
bool ai_will_grant_access(sys::state &state, dcon::nation_id target, dcon::nation_id from)
Definition: ai.cpp:351
bool will_be_crisis_primary_attacker(sys::state &state, dcon::nation_id n)
Definition: ai.cpp:2094
bool will_join_crisis_with_offer(sys::state &state, dcon::nation_id n, sys::full_wg offer)
Definition: ai.cpp:2241
bool will_join_war(sys::state &state, dcon::nation_id n, dcon::war_id w, bool as_attacker)
Definition: ai.cpp:2979
bool will_be_crisis_primary_defender(sys::state &state, dcon::nation_id n)
Definition: ai.cpp:2136
bool will_accept_crisis_peace_offer(sys::state &state, dcon::nation_id to, bool is_concession, bool missing_wg)
Definition: ai.cpp:2546
bool can_state_transfer(sys::state &state, dcon::nation_id asker, dcon::nation_id target, dcon::state_definition_id sid)
Definition: commands.cpp:2462
bool can_call_to_arms(sys::state &state, dcon::nation_id asker, dcon::nation_id target, dcon::war_id w, bool ignore_cost)
Definition: commands.cpp:2517
bool can_ask_for_access(sys::state &state, dcon::nation_id asker, dcon::nation_id target, bool ignore_cost)
Definition: commands.cpp:2309
bool can_ask_for_alliance(sys::state &state, dcon::nation_id asker, dcon::nation_id target, bool ignore_cost)
Definition: commands.cpp:2384
constexpr int32_t expiration_in_days
bool can_accept(sys::state &state, message const &m)
void decline(sys::state &state, message const &m)
void update_pending(sys::state &state)
void accept(sys::state &state, message const &m)
void post(sys::state &state, message const &m)
Pushes a diplomatic message to the list of pending diplomatic requests for the specified recipient (m...
bool can_accept_crisis_peace_offer(sys::state &state, dcon::nation_id from, dcon::nation_id to, dcon::peace_offer_id peace)
bool ai_will_accept(sys::state &state, message const &m)
Returns the appropriate acceptance evaluation for a given diplomatic message. It is required to defin...
bool can_accept_crisis_offer(sys::state &state, dcon::nation_id from, dcon::nation_id to, sys::full_wg offer)
void add_to_crisis_with_offer(sys::state &state, dcon::nation_id from, dcon::nation_id to, sys::full_wg offer)
constexpr uint32_t is_not_constructing_cb
Definition: military.hpp:12
constexpr uint32_t always
Definition: military.hpp:10
float crisis_cb_addition_infamy_cost(sys::state &state, dcon::cb_type_id type, dcon::nation_id from, dcon::nation_id target, dcon::state_definition_id cb_state)
Definition: military.cpp:2030
void add_to_war(sys::state &state, dcon::war_id w, dcon::nation_id n, bool as_attacker, bool on_war_creation)
Definition: military.cpp:2368
void reject_peace_offer(sys::state &state, dcon::peace_offer_id offer)
Definition: military.cpp:3802
war_role get_role(sys::state const &state, dcon::war_id w, dcon::nation_id n)
Definition: military.cpp:2501
bool is_attacker(sys::state &state, dcon::war_id w, dcon::nation_id n)
Definition: military.cpp:2493
bool cb_instance_conditions_satisfied(sys::state &state, dcon::nation_id actor, dcon::nation_id target, dcon::cb_type_id cb, dcon::state_definition_id st, dcon::national_identity_id tag, dcon::nation_id secondary)
Definition: military.cpp:471
void implement_peace_offer(sys::state &state, dcon::peace_offer_id offer)
Definition: military.cpp:3505
void cleanup_crisis_peace_offer(sys::state &state, dcon::peace_offer_id peace)
Definition: nations.cpp:2597
void accept_crisis_peace_offer(sys::state &state, dcon::nation_id from, dcon::nation_id to, dcon::peace_offer_id peace)
Definition: nations.cpp:2605
void reject_crisis_participation(sys::state &state)
Definition: nations.cpp:2536
void make_alliance(sys::state &state, dcon::nation_id a, dcon::nation_id b)
Definition: nations.cpp:2037
void crisis_add_wargoal(std::vector< sys::full_wg > &list, sys::full_wg wg)
Definition: nations.cpp:2430
void add_as_primary_crisis_defender(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:2482
void add_as_primary_crisis_attacker(sys::state &state, dcon::nation_id n)
Definition: nations.cpp:2496
void update_cached_values(sys::state &state)
Definition: nations.cpp:127
void adjust_relationship(sys::state &state, dcon::nation_id a, dcon::nation_id b, float delta)
Definition: nations.cpp:1660
void post(sys::state &state, message &&m)
void update_connected_regions(sys::state &state)
Definition: province.cpp:30
void update_cached_values(sys::state &state)
Definition: province.cpp:305
void change_province_owner(sys::state &state, dcon::province_id id, dcon::nation_id new_owner)
Definition: province.cpp:716
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
Definition: text.cpp:1923
Holds data regarding a diplomatic message between two specified nations at a certain date,...
dcon::nation_id target_nation
dcon::nation_id secondary_nation
dcon::cb_type_id cb
dcon::national_identity_id wg_tag
dcon::state_definition_id state
Holds important data about the game world, state, and other data regarding windowing,...