Project Alice
Loading...
Searching...
No Matches
events.cpp
Go to the documentation of this file.
1#include "events.hpp"
2#include "effects.hpp"
3#include "gui_event.hpp"
4#include "prng.hpp"
5#include "system_state.hpp"
6#include "triggers.hpp"
7
8namespace event {
9
11 return opt.effect || opt.name;
12}
13
15 for(auto i = state.pending_n_event.size(); i-- > 0;) {
16 if(state.pending_n_event[i].date == e.date && state.pending_n_event[i].e == e.e &&
17 state.pending_n_event[i].from_slot == e.from_slot && state.pending_n_event[i].n == e.n &&
18 state.pending_n_event[i].primary_slot == e.primary_slot && state.pending_n_event[i].r_hi == e.r_hi &&
19 state.pending_n_event[i].r_lo == e.r_lo) {
20
21 if(opt > state.world.national_event_get_options(e.e).size() || !is_valid_option(state.world.national_event_get_options(e.e)[opt]))
22 return; // invalid option
23
24 state.pending_n_event[i] = state.pending_n_event.back();
25 state.pending_n_event.pop_back();
26
27 if(state.world.national_event_get_options(e.e)[opt].effect) {
28 effect::execute(state, state.world.national_event_get_options(e.e)[opt].effect, e.primary_slot, trigger::to_generic(e.n),
29 e.from_slot, e.r_lo, e.r_hi);
30 }
31 return;
32 }
33 }
34}
35
37 for(auto i = state.pending_f_n_event.size(); i-- > 0;) {
38 if(state.pending_f_n_event[i].date == e.date && state.pending_f_n_event[i].e == e.e && state.pending_f_n_event[i].n == e.n &&
39 state.pending_f_n_event[i].r_hi == e.r_hi && state.pending_f_n_event[i].r_lo == e.r_lo) {
40
41 if(opt > state.world.free_national_event_get_options(e.e).size() || !is_valid_option(state.world.free_national_event_get_options(e.e)[opt]))
42 return; // invalid option
43
44 state.pending_f_n_event[i] = state.pending_f_n_event.back();
45 state.pending_f_n_event.pop_back();
46
47 if(state.world.free_national_event_get_options(e.e)[opt].effect) {
48 effect::execute(state, state.world.free_national_event_get_options(e.e)[opt].effect, trigger::to_generic(e.n),
49 trigger::to_generic(e.n), 0, e.r_lo, e.r_hi);
50 }
51 return;
52 }
53 }
54}
55
57 for(auto i = state.pending_p_event.size(); i-- > 0;) {
58 if(state.pending_p_event[i].date == e.date && state.pending_p_event[i].e == e.e &&
59 state.pending_p_event[i].from_slot == e.from_slot && state.pending_p_event[i].p == e.p &&
60 state.pending_p_event[i].r_hi == e.r_hi && state.pending_p_event[i].r_lo == e.r_lo) {
61
62 if(opt > state.world.provincial_event_get_options(e.e).size() || !is_valid_option(state.world.provincial_event_get_options(e.e)[opt]))
63 return; // invalid option
64
65 state.pending_p_event[i] = state.pending_p_event.back();
66 state.pending_p_event.pop_back();
67
68 if(state.world.provincial_event_get_options(e.e)[opt].effect) {
69 effect::execute(state, state.world.provincial_event_get_options(e.e)[opt].effect, trigger::to_generic(e.p),
71 }
72
73 return;
74 }
75 }
76}
78 for(auto i = state.pending_f_p_event.size(); i-- > 0;) {
79 if(state.pending_f_p_event[i].date == e.date && state.pending_f_p_event[i].e == e.e && state.pending_f_p_event[i].p == e.p &&
80 state.pending_f_p_event[i].r_hi == e.r_hi && state.pending_f_p_event[i].r_lo == e.r_lo) {
81
82 if(opt > state.world.free_provincial_event_get_options(e.e).size() || !is_valid_option(state.world.free_provincial_event_get_options(e.e)[opt]))
83 return; // invalid option
84
85 state.pending_f_p_event[i] = state.pending_f_p_event.back();
86 state.pending_f_p_event.pop_back();
87
88 if(state.world.free_provincial_event_get_options(e.e)[opt].effect) {
89 effect::execute(state, state.world.free_provincial_event_get_options(e.e)[opt].effect, trigger::to_generic(e.p),
90 trigger::to_generic(e.p), -1, e.r_lo, e.r_hi);
91 }
92 return;
93 }
94 }
95}
96
97template<typename T>
99 auto fat_id = dcon::fatten(state.world, id);
100 bool b = false;
101 for(const auto& opt : fat_id.get_options()) {
102 if(!is_valid_option(opt))
103 break;
104 b = true;
105 }
106 return b;
107}
108
109void trigger_national_event(sys::state& state, dcon::national_event_id e, dcon::nation_id n, uint32_t r_lo, uint32_t r_hi, int32_t primary_slot, slot_type pt, int32_t from_slot, slot_type ft) {
110 if(!state.world.national_event_get_name(e) && !state.world.national_event_get_immediate_effect(e) && !event_has_options(state, e))
111 return; // event without data
112 if(ft == slot_type::province)
113 assert(dcon::fatten(state.world, state.world.province_get_nation_from_province_ownership(trigger::to_prov(from_slot))).is_valid());
114
115
116 if(state.world.national_event_get_is_major(e)) {
118 [ev = pending_human_n_event{r_lo, r_hi + 1, primary_slot, from_slot, state.current_date, e, n, pt, ft}](sys::state& state, text::layout_base& contents) {
121
122 {
123 auto box = text::open_layout_box(contents);
124 text::add_to_layout_box(state, contents, box, state.world.national_event_get_name(ev.e), m);
125 text::close_layout_box(contents, box);
126 }
127 {
128 auto box = text::open_layout_box(contents);
130 text::add_to_layout_box(state, contents, box, state.world.national_event_get_description(ev.e), m);
131 text::close_layout_box(contents, box);
132 }
133 },
134 "msg_m_event_title",
135 n, dcon::nation_id{}, dcon::nation_id{},
137 });
138 } else if(n == state.local_player_nation) {
140 [ev = pending_human_n_event{r_lo, r_hi + 1, primary_slot, from_slot, state.current_date, e, n, pt, ft}](sys::state& state, text::layout_base& contents) {
143
144 {
145 auto box = text::open_layout_box(contents);
146 text::add_to_layout_box(state, contents, box, state.world.national_event_get_name(ev.e), m);
147 text::close_layout_box(contents, box);
148 }
149 {
150 auto box = text::open_layout_box(contents);
152 text::add_to_layout_box(state, contents, box, state.world.national_event_get_description(ev.e), m);
153 text::close_layout_box(contents, box);
154 }
155 },
156 "msg_n_event_title",
157 n, dcon::nation_id{}, dcon::nation_id{},
159 });
160 }
161
162 if(auto immediate = state.world.national_event_get_immediate_effect(e); immediate) {
163 effect::execute(state, immediate, primary_slot, trigger::to_generic(n), from_slot, r_lo, r_hi);
164 }
165 if(state.world.nation_get_is_player_controlled(n)) {
166 pending_human_n_event new_event{r_lo, r_hi + 1, primary_slot, from_slot, state.current_date, e, n, pt, ft};
167 state.pending_n_event.push_back(new_event);
168 if(n == state.local_player_nation)
169 state.new_n_event.push(new_event);
170 } else {
171 auto& opt = state.world.national_event_get_options(e);
172 float total = 0.0f;
173 float odds[sys::max_event_options] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f , 0.0f };
174 for(uint32_t i = 0; i < opt.size(); ++i) {
175 if(opt[i].ai_chance) { //opt[i].effect may not be defined, but it may still be present
176 odds[i] = trigger::evaluate_multiplicative_modifier(state, opt[i].ai_chance, primary_slot, trigger::to_generic(n), from_slot);
177 total += odds[i];
178 }
179 }
180
181 if(total > 0.0f) {
182 auto rvalue = float(rng::get_random(state, uint32_t(e.index() ^ n.index() << 5)) & 0xFFFF) / float(0xFFFF + 1);
183 for(uint32_t i = 0; i < opt.size(); ++i) {
184 if(opt[i].ai_chance) {
185 rvalue -= odds[i] / total;
186 if(rvalue < 0.0f) {
187 if(opt[i].effect) {
188 effect::execute(state, opt[i].effect, primary_slot, trigger::to_generic(n), from_slot, r_lo, r_hi + 1);
189 }
190 return;
191 }
192 }
193 }
194 }
195
196 if(opt[0].effect) {
197 effect::execute(state, opt[0].effect, primary_slot, trigger::to_generic(n), from_slot, r_lo, r_hi + 1);
198 }
199 }
200}
201void trigger_national_event(sys::state& state, dcon::national_event_id e, dcon::nation_id n, uint32_t r_hi, uint32_t r_lo, int32_t from_slot, slot_type ft) {
202 trigger_national_event(state, e, n, r_hi, r_lo, trigger::to_generic(n), slot_type::nation, from_slot, ft);
203}
204void trigger_national_event(sys::state& state, dcon::free_national_event_id e, dcon::nation_id n, uint32_t r_lo, uint32_t r_hi) {
205 if(state.world.free_national_event_get_only_once(e) && state.world.free_national_event_get_has_been_triggered(e))
206 return;
207 if(!state.world.free_national_event_get_name(e) && !state.world.free_national_event_get_immediate_effect(e) && !event_has_options(state, e))
208 return; // event without data
209
210 state.world.free_national_event_set_has_been_triggered(e, true);
211 if(state.world.free_national_event_get_is_major(e)) {
213 [ev = pending_human_f_n_event{r_lo, r_hi + 1, state.current_date, e, n}](sys::state& state, text::layout_base& contents) {
216
217 {
218 auto box = text::open_layout_box(contents);
219 text::add_to_layout_box(state, contents, box, state.world.free_national_event_get_name(ev.e), m);
220 text::close_layout_box(contents, box);
221 }
222 {
223 auto box = text::open_layout_box(contents);
225 text::add_to_layout_box(state, contents, box, state.world.free_national_event_get_description(ev.e), m);
226 text::close_layout_box(contents, box);
227 }
228 },
229 "msg_m_event_title",
230 n, dcon::nation_id{}, dcon::nation_id{},
232 });
233 } else if(n == state.local_player_nation) {
235 [ev = pending_human_f_n_event{r_lo, r_hi + 1, state.current_date, e, n}](sys::state& state, text::layout_base& contents) {
238
239 {
240 auto box = text::open_layout_box(contents);
241 text::add_to_layout_box(state, contents, box, state.world.free_national_event_get_name(ev.e), m);
242 text::close_layout_box(contents, box);
243 }
244 {
245 auto box = text::open_layout_box(contents);
247 text::add_to_layout_box(state, contents, box, state.world.free_national_event_get_description(ev.e), m);
248 text::close_layout_box(contents, box);
249 }
250 },
251 "msg_n_event_title",
252 n, dcon::nation_id{}, dcon::nation_id{},
254 });
255 }
256 if(auto immediate = state.world.free_national_event_get_immediate_effect(e); immediate) {
257 effect::execute(state, immediate, trigger::to_generic(n), trigger::to_generic(n), 0, r_lo, r_hi);
258 }
259 if(state.world.nation_get_is_player_controlled(n)) {
260 pending_human_f_n_event new_event{r_lo, r_hi + 1, state.current_date, e, n};
261 state.pending_f_n_event.push_back(new_event);
262 if(n == state.local_player_nation)
263 state.new_f_n_event.push(new_event);
264 } else {
265 auto& opt = state.world.free_national_event_get_options(e);
266 float total = 0.0f;
267 float odds[sys::max_event_options] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
268 for(uint32_t i = 0; i < opt.size(); ++i) {
269 if(opt[i].ai_chance) { //effect may not be present but chance may
271 total += odds[i];
272 }
273 }
274
275 if(total > 0.0f) {
276 auto rvalue = float(rng::get_random(state, uint32_t((e.index() << 3) ^ n.index())) & 0xFFFF) / float(0xFFFF + 1);
277 for(uint32_t i = 0; i < opt.size(); ++i) {
278 if(opt[i].ai_chance) {
279 rvalue -= odds[i] / total;
280 if(rvalue < 0.0f) {
281 if(opt[i].effect) {
282 effect::execute(state, opt[i].effect, trigger::to_generic(n), trigger::to_generic(n), 0, r_lo, r_hi + 1);
283 }
284 return;
285 }
286 }
287 }
288 }
289
290 if(opt[0].effect) {
291 effect::execute(state, opt[0].effect, trigger::to_generic(n), trigger::to_generic(n), 0, r_lo, r_hi + 1);
292 }
293 }
294}
295void trigger_provincial_event(sys::state& state, dcon::provincial_event_id e, dcon::province_id p, uint32_t r_hi, uint32_t r_lo, int32_t from_slot, slot_type ft) {
296 if(!state.world.provincial_event_get_name(e) && !state.world.provincial_event_get_immediate_effect(e) && !event_has_options(state, e))
297 return; // event without data
298 if(ft == slot_type::province)
299 assert(dcon::fatten(state.world, state.world.province_get_nation_from_province_ownership(trigger::to_prov(from_slot))).is_valid());
300
301 if(auto immediate = state.world.provincial_event_get_immediate_effect(e); immediate) {
302 effect::execute(state, immediate, trigger::to_generic(p), trigger::to_generic(p), from_slot, r_lo, r_hi);
303 }
304 auto owner = state.world.province_get_nation_from_province_ownership(p);
305 if(owner == state.local_player_nation) {
307 [ev = pending_human_p_event{r_lo, r_hi, from_slot, state.current_date, e, p, ft}](sys::state& state, text::layout_base& contents) {
310
311 {
312 auto box = text::open_layout_box(contents);
313 text::add_to_layout_box(state, contents, box, state.world.provincial_event_get_name(ev.e), m);
314 text::close_layout_box(contents, box);
315 }
316 {
317 auto box = text::open_layout_box(contents);
319 text::add_to_layout_box(state, contents, box, state.world.provincial_event_get_description(ev.e), m);
320 text::close_layout_box(contents, box);
321 }
322 },
323 "msg_p_event_title",
324 owner, dcon::nation_id{}, dcon::nation_id{},
326 });
327 }
328 if(state.world.nation_get_is_player_controlled(owner)) {
329 pending_human_p_event new_event{r_lo, r_hi, from_slot, state.current_date, e, p, ft};
330 state.pending_p_event.push_back(new_event);
331 if(owner == state.local_player_nation)
332 state.new_p_event.push(new_event);
333 } else {
334 auto& opt = state.world.provincial_event_get_options(e);
335 float total = 0.0f;
336 float odds[sys::max_event_options] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
337 for(uint32_t i = 0; i < opt.size(); ++i) {
338 if(opt[i].ai_chance) { //effect may not be present but chance may
339 odds[i] = trigger::evaluate_multiplicative_modifier(state, opt[i].ai_chance, trigger::to_generic(p), trigger::to_generic(p), from_slot);
340 total += odds[i];
341 }
342 }
343
344 if(total > 0.0f) {
345 auto rvalue = float(rng::get_random(state, uint32_t(e.index() ^ p.index() << 5)) & 0xFFFF) / float(0xFFFF + 1);
346 for(uint32_t i = 0; i < opt.size(); ++i) {
347 if(opt[i].ai_chance) {
348 rvalue -= odds[i] / total;
349 if(rvalue < 0.0f) {
350 if(opt[i].effect) {
351 effect::execute(state, opt[i].effect, trigger::to_generic(p), trigger::to_generic(p), from_slot, r_lo, r_hi);
352 }
353 return;
354 }
355 }
356 }
357 }
358
359 if(opt[0].effect) {
360 effect::execute(state, opt[0].effect, trigger::to_generic(p), trigger::to_generic(p), from_slot, r_lo, r_hi);
361 }
362 }
363}
364void trigger_provincial_event(sys::state& state, dcon::free_provincial_event_id e, dcon::province_id p, uint32_t r_hi,
365 uint32_t r_lo) {
366 if(state.world.free_provincial_event_get_only_once(e) && state.world.free_provincial_event_get_has_been_triggered(e))
367 return;
368 if(!state.world.free_provincial_event_get_name(e) && !state.world.free_provincial_event_get_immediate_effect(e) && !event_has_options(state, e))
369 return; // event without data
370
371 state.world.free_provincial_event_set_has_been_triggered(e, true);
372 if(auto immediate = state.world.free_provincial_event_get_immediate_effect(e); immediate) {
373 effect::execute(state, immediate, trigger::to_generic(p), trigger::to_generic(p), 0, r_lo, r_hi);
374 }
375 auto owner = state.world.province_get_nation_from_province_ownership(p);
376 if(owner == state.local_player_nation) {
378 [ev = pending_human_f_p_event{r_lo, r_hi, state.current_date, e, p}](sys::state& state, text::layout_base& contents) {
381
382 {
383 auto box = text::open_layout_box(contents);
384 text::add_to_layout_box(state, contents, box, state.world.free_provincial_event_get_name(ev.e), m);
385 text::close_layout_box(contents, box);
386 }
387 {
388 auto box = text::open_layout_box(contents);
390 text::add_to_layout_box(state, contents, box, state.world.free_provincial_event_get_description(ev.e), m);
391 text::close_layout_box(contents, box);
392 }
393 },
394 "msg_p_event_title",
395 owner, dcon::nation_id{}, dcon::nation_id{},
397 });
398 }
399 if(state.world.nation_get_is_player_controlled(owner)) {
400 pending_human_f_p_event new_event{r_lo, r_hi, state.current_date, e, p};
401 state.pending_f_p_event.push_back(new_event);
402 if(owner == state.local_player_nation)
403 state.new_f_p_event.push(new_event);
404 } else {
405 auto& opt = state.world.free_provincial_event_get_options(e);
406 float total = 0.0f;
407 float odds[sys::max_event_options] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
408 for(uint32_t i = 0; i < opt.size(); ++i) {
409 if(opt[i].ai_chance) { //effect may not be present but chance may
411 total += odds[i];
412 }
413 }
414
415 if(total > 0.0f) {
416 auto rvalue = float(rng::get_random(state, uint32_t(e.index() ^ p.index() << 5)) & 0xFFFF) / float(0xFFFF + 1);
417 for(uint32_t i = 0; i < opt.size(); ++i) {
418 if(opt[i].ai_chance) {
419 rvalue -= odds[i] / total;
420 if(rvalue < 0.0f) {
421 if(opt[i].effect) {
423 }
424 return;
425 }
426 }
427 }
428 }
429
430 if(opt[0].effect) {
432 }
433 }
434}
435
437 dcon::nation_id n;
438 dcon::free_national_event_id e;
439
440 bool operator==(event_nation_pair const& other) const noexcept {
441 return other.n == n && other.e == e;
442 }
443 bool operator<(event_nation_pair const& other) const noexcept {
444 return other.n != n ? (n.value < other.n.value) : (e.value < other.e.value);
445 }
446};
448 dcon::province_id p;
449 dcon::free_provincial_event_id e;
450
451 bool operator==(event_prov_pair const& other) const noexcept {
452 return other.p == p && other.e == e;
453 }
454 bool operator<(event_prov_pair const& other) const noexcept {
455 return other.p != p ? (p.value < other.p.value) : (e.value < other.e.value);
456 }
457};
458
459bool would_be_duplicate_instance(sys::state& state, dcon::national_event_id e, dcon::nation_id n, sys::date date) {
460 if(state.world.national_event_get_allow_multiple_instances(e))
461 return false;
462 for(int32_t i = 0; i < int32_t(state.future_n_event.size()); i++) {
463 auto const& nev = state.future_n_event[i];
464 if(nev.e == e
465 && nev.n == n
466 && nev.date == date) {
467 return true;
468 }
469 }
470 return false;
471}
472
474 for(uint32_t i = 0; i < uint32_t(state.defines.alice_max_event_iterations); i++) {
475 bool fired_n = false;
476 uint32_t n_n_events = uint32_t(state.future_n_event.size());
477 for(int32_t j = int32_t(n_n_events - 1); j >= 0; j--) {
478 auto const& e = state.future_n_event[j];
479 if(e.date <= state.current_date) {
480 trigger_national_event(state, e.e, e.n, e.r_lo, e.r_hi, e.primary_slot, e.pt, e.from_slot, e.ft);
481 fired_n = true;
482 }
483 }
484 if(fired_n) {
485 for(int32_t j = int32_t(n_n_events - 1); j >= 0; j--) {
486 auto const& e = state.future_n_event[j];
487 if(e.date <= state.current_date) {
488 std::swap(state.future_n_event[j], state.future_n_event[state.future_n_event.size() - 1]);
489 state.future_n_event.pop_back();
490 }
491 }
492 }
493 //
494 bool fired_p = false;
495 uint32_t n_p_events = uint32_t(state.future_p_event.size());
496 for(int32_t j = int32_t(n_p_events - 1); j >= 0; j--) {
497 auto const& e = state.future_p_event[j];
498 if(e.date <= state.current_date) {
499 trigger_provincial_event(state, e.e, e.p, e.r_lo, e.r_hi, e.from_slot, e.ft);
500 fired_p = true;
501 }
502 }
503 if(fired_p) {
504 for(int32_t j = int32_t(n_p_events - 1); j >= 0; j--) {
505 auto const& e = state.future_p_event[j];
506 if(e.date <= state.current_date) {
507 std::swap(state.future_p_event[j], state.future_p_event[state.future_p_event.size() - 1]);
508 state.future_p_event.pop_back();
509 }
510 }
511 }
512 if(!fired_p && !fired_n)
513 break;
514 }
515}
516
518 uint32_t n_block_size = state.world.free_national_event_size() / 32;
519 uint32_t p_block_size = state.world.free_provincial_event_size() / 32;
520
521 uint32_t block_index = (state.current_date.value & 31);
522
523 concurrency::combinable<std::vector<event_nation_pair>> events_triggered;
524
525 auto n_block_end = block_index == 31 ? state.world.free_national_event_size() : n_block_size * (block_index + 1);
526 concurrency::parallel_for(n_block_size * block_index, n_block_end, [&](uint32_t i) {
527 dcon::free_national_event_id id{dcon::national_event_id::value_base_t(i)};
528 auto mod = state.world.free_national_event_get_mtth(id);
529 auto t = state.world.free_national_event_get_trigger(id);
530
531 if(state.world.free_national_event_get_only_once(id) == false || state.world.free_national_event_get_has_been_triggered(id) == false) {
532 ve::execute_serial_fast<dcon::nation_id>(state.world.nation_size(), [&](auto ids) {
533 /*
534 For national events: the base factor (scaled to days) is multiplied with all modifiers that hold. If the value is
535 non positive, we take the probability of the event occurring as 0.000001. If the value is less than 0.001, the
536 event is guaranteed to happen. Otherwise, the probability is the multiplicative inverse of the value.
537 */
538 auto some_exist = t
539 ? (state.world.nation_get_owned_province_count(ids) != 0) && trigger::evaluate(state, t, trigger::to_generic(ids), trigger::to_generic(ids), 0)
540 : (state.world.nation_get_owned_province_count(ids) != 0);
541 if(ve::compress_mask(some_exist).v != 0) {
542 auto chances = mod ?
543 trigger::evaluate_multiplicative_modifier(state, mod, trigger::to_generic(ids), trigger::to_generic(ids), 0) : ve::fp_vector{ 1.0f };
544 auto adj_chance = 1.0f - ve::select(chances <= 1.0f, 1.0f, 1.0f / (chances));
545 auto adj_chance_2 = adj_chance * adj_chance;
546 auto adj_chance_4 = adj_chance_2 * adj_chance_2;
547 auto adj_chance_8 = adj_chance_4 * adj_chance_4;
548 auto adj_chance_16 = adj_chance_8 * adj_chance_8;
549
550 ve::apply(
551 [&](dcon::nation_id n, float c, bool condition) {
552 auto owned_range = state.world.nation_get_province_ownership(n);
553 if(condition && owned_range.begin() != owned_range.end()) {
554 if(float(rng::get_random(state, uint32_t((i << 1) ^ n.index())) & 0xFFFFFF) / float(0xFFFFFF + 1) >= c) {
555 events_triggered.local().push_back(event_nation_pair{n, id});
556 }
557 }
558 },
559 ids, adj_chance_16, some_exist);
560 }
561 });
562
563 }
564 });
565
566 auto total_vector = events_triggered.combine([](auto& a, auto& b) {
567 std::vector<event_nation_pair> result(a.begin(), a.end());
568 result.insert(result.end(), b.begin(), b.end());
569 return result;
570 });
571 std::sort(total_vector.begin(), total_vector.end());
572 for(auto& v : total_vector) {
573 if(trigger::evaluate(state, state.world.free_national_event_get_trigger(v.e), trigger::to_generic(v.n), trigger::to_generic(v.n), 0)) {
574 event::trigger_national_event(state, v.e, v.n, uint32_t((state.current_date.value) ^ (v.e.value << 3)), uint32_t(v.n.value));
575 }
576 }
577
578 concurrency::combinable<std::vector<event_prov_pair>> p_events_triggered;
579
580 auto p_block_end = block_index == 31 ? state.world.free_provincial_event_size() : p_block_size * (block_index + 1);
581 concurrency::parallel_for(p_block_size * block_index, p_block_end, [&](uint32_t i) {
582 dcon::free_provincial_event_id id{dcon::free_provincial_event_id::value_base_t(i)};
583 auto mod = state.world.free_provincial_event_get_mtth(id);
584 auto t = state.world.free_provincial_event_get_trigger(id);
585
586 if(state.world.free_provincial_event_get_only_once(id) == false || state.world.free_provincial_event_get_has_been_triggered(id) == false) {
587 ve::execute_serial_fast<dcon::province_id>(uint32_t(state.province_definitions.first_sea_province.index()),
588 [&](ve::contiguous_tags<dcon::province_id> ids) {
589 /*
590 The probabilities for province events are calculated in the same way, except that they are twice as likely to
591 happen.
592 */
593 auto owners = state.world.province_get_nation_from_province_ownership(ids);
594 auto some_exist = t ? (owners != dcon::nation_id{}) &&
596 : (owners != dcon::nation_id{});
597 if(ve::compress_mask(some_exist).v != 0) {
598 auto chances = mod
600 : ve::fp_vector{ 2.0f };
601 auto adj_chance = 1.0f - ve::select(chances <= 2.0f, 1.0f, 2.0f / chances);
602 auto adj_chance_2 = adj_chance * adj_chance;
603 auto adj_chance_4 = adj_chance_2 * adj_chance_2;
604 auto adj_chance_8 = adj_chance_4 * adj_chance_4;
605 auto adj_chance_16 = adj_chance_8 * adj_chance_8;
606
607 ve::apply(
608 [&](dcon::province_id p, dcon::nation_id o, float c, bool condition) {
609 if(condition) {
610 if(float(rng::get_random(state, uint32_t((i << 1) ^ p.index())) & 0xFFFFFF) / float(0xFFFFFF + 1) >= c) {
611 p_events_triggered.local().push_back(event_prov_pair{ p, id });
612 }
613 }
614 },
615 ids, owners, adj_chance_16, some_exist);
616 }
617 });
618 }
619 });
620
621 auto total_p_vector = p_events_triggered.combine([](auto& a, auto& b) {
622 std::vector<event_prov_pair> result(a.begin(), a.end());
623 result.insert(result.end(), b.begin(), b.end());
624 return result;
625 });
626 std::sort(total_p_vector.begin(), total_p_vector.end());
627 for(auto& v : total_p_vector) {
628 if(trigger::evaluate(state, state.world.free_provincial_event_get_trigger(v.e), trigger::to_generic(v.p), trigger::to_generic(v.p), 0)) {
629 trigger_provincial_event(state, v.e, v.p, uint32_t((state.current_date.value) ^ (v.e.value << 3)), uint32_t(v.p.value));
630 }
631 }
632
633 for(auto i = state.pending_n_event.size(); i-- > 0;) {
634 if(state.pending_n_event[i].date + expiration_in_days <= state.current_date) { // expired
635 auto& opt = state.world.national_event_get_options(state.pending_n_event[i].e);
636
637 if(opt[0].effect) {
638 effect::execute(state, opt[0].effect, state.pending_n_event[i].primary_slot,
639 trigger::to_generic(state.pending_n_event[i].n), state.pending_n_event[i].from_slot, state.pending_n_event[i].r_lo,
640 state.pending_n_event[i].r_hi);
641 }
642
643 // TODO: notify
644
645 state.pending_n_event[i] = state.pending_n_event.back();
646 state.pending_n_event.pop_back();
647 }
648 }
649
650 for(auto i = state.pending_f_n_event.size(); i-- > 0;) {
651 if(state.pending_f_n_event[i].date + expiration_in_days <= state.current_date) { // expired
652 auto& opt = state.world.free_national_event_get_options(state.pending_f_n_event[i].e);
653
654 if(opt[0].effect) {
655 effect::execute(state, opt[0].effect, trigger::to_generic(state.pending_f_n_event[i].n),
656 trigger::to_generic(state.pending_f_n_event[i].n), 0, state.pending_f_n_event[i].r_lo,
657 state.pending_f_n_event[i].r_hi);
658 }
659
660 // TODO: notify
661
662 state.pending_f_n_event[i] = state.pending_f_n_event.back();
663 state.pending_f_n_event.pop_back();
664 }
665 }
666
667 for(auto i = state.pending_p_event.size(); i-- > 0;) {
668 if(state.pending_p_event[i].date + expiration_in_days <= state.current_date) { // expired
669 auto& opt = state.world.provincial_event_get_options(state.pending_p_event[i].e);
670
671 if(opt[0].effect) {
672 effect::execute(state, opt[0].effect, trigger::to_generic(state.pending_p_event[i].p),
673 trigger::to_generic(state.pending_p_event[i].p), state.pending_p_event[i].from_slot, state.pending_p_event[i].r_lo,
674 state.pending_p_event[i].r_hi);
675 }
676
677 // TODO: notify
678
679 state.pending_p_event[i] = state.pending_p_event.back();
680 state.pending_p_event.pop_back();
681 }
682 }
683
684 for(auto i = state.pending_f_p_event.size(); i-- > 0;) {
685 if(state.pending_f_p_event[i].date + expiration_in_days <= state.current_date) { // expired
686 auto& opt = state.world.free_provincial_event_get_options(state.pending_f_p_event[i].e);
687
688 if(opt[0].effect) {
689 effect::execute(state, opt[0].effect, trigger::to_generic(state.pending_f_p_event[i].p),
690 trigger::to_generic(state.pending_f_p_event[i].p), 0, state.pending_f_p_event[i].r_lo,
691 state.pending_f_p_event[i].r_hi);
692 }
693
694 // TODO: notify
695
696 state.pending_f_p_event[i] = state.pending_f_p_event.back();
697 state.pending_f_p_event.pop_back();
698 }
699 }
700
702}
703
705 dcon::national_event_id e;
706 int32_t chance;
707};
708
709void fire_fixed_event(sys::state& state, std::vector<nations::fixed_event> const& v, int32_t primary_slot, slot_type pt, dcon::nation_id this_slot, int32_t from_slot, slot_type ft) {
710 static std::vector<internal_n_epair> valid_list;
711 valid_list.clear();
712 int32_t total_chances = 0;
713 for(auto& fe : v) {
714 if(!fe.condition || trigger::evaluate(state, fe.condition, primary_slot, trigger::to_generic(this_slot), from_slot)) {
715 total_chances += fe.chance;
716 valid_list.push_back(internal_n_epair{fe.id, fe.chance});
717 }
718 }
719 if(auto possible_events = valid_list.size(); possible_events > 0) {
720 int32_t random_value = int32_t(rng::get_random(state, uint32_t(primary_slot + (state.world.nation_get_owned_province_count(this_slot) << 3))) % total_chances);
721 for(auto& fe : valid_list) {
722 random_value -= fe.chance;
723 if(random_value < 0) {
724 trigger_national_event(state, fe.e, this_slot, state.current_date.value, uint32_t(primary_slot), primary_slot, pt, from_slot, ft);
725 return;
726 }
727 }
728 }
729}
730
731void fire_fixed_event(sys::state& state, std::vector<nations::fixed_election_event> const& v, int32_t primary_slot, slot_type pt, dcon::nation_id this_slot, int32_t from_slot, slot_type ft) {
732 static std::vector<internal_n_epair> valid_list;
733 valid_list.clear();
734 int32_t total_chances = 0;
735 for(auto& fe : v) {
736 if(!fe.condition || trigger::evaluate(state, fe.condition, primary_slot, trigger::to_generic(this_slot), from_slot)) {
737 total_chances += fe.chance;
738 valid_list.push_back(internal_n_epair{ fe.id, fe.chance });
739 }
740 }
741 if(auto possible_events = valid_list.size(); possible_events > 0) {
742 int32_t random_value = int32_t(rng::get_random(state, uint32_t(primary_slot + (state.world.nation_get_owned_province_count(this_slot) << 3))) % total_chances);
743 for(auto& fe : valid_list) {
744 random_value -= fe.chance;
745 if(random_value < 0) {
746 trigger_national_event(state, fe.e, this_slot, state.current_date.value, uint32_t(primary_slot), primary_slot, pt, from_slot, ft);
747 return;
748 }
749 }
750 }
751}
752
754 dcon::provincial_event_id e;
755 int32_t chance;
756};
757
758void fire_fixed_event(sys::state& state, std::vector<nations::fixed_province_event> const& v, dcon::province_id prov,
759 int32_t from_slot, slot_type ft) {
760 static std::vector<internal_p_epair> valid_list;
761 valid_list.clear();
762
763 int32_t total_chances = 0;
764
765 for(auto& fe : v) {
766 if(!fe.condition || trigger::evaluate(state, fe.condition, trigger::to_generic(prov), trigger::to_generic(prov), from_slot)) {
767 total_chances += fe.chance;
768 valid_list.push_back(internal_p_epair{fe.id, fe.chance});
769 }
770 }
771
772 auto possible_events = valid_list.size();
773 if(possible_events > 0) {
774
775 int32_t random_value = int32_t(rng::get_random(state, uint32_t(prov.index())) % total_chances);
776
777 for(auto& fe : valid_list) {
778 random_value -= fe.chance;
779 if(random_value < 0) {
780 trigger_provincial_event(state, fe.e, prov, state.current_date.value, uint32_t(prov.index()), from_slot, ft);
781 return;
782 }
783 }
784 }
785}
786
787dcon::issue_id get_election_event_issue(sys::state& state, dcon::national_event_id e) {
788 for(auto const& fe : state.national_definitions.on_election_tick) {
789 if(fe.id == e) {
790 return fe.issue_group;
791 }
792 }
793 return dcon::issue_id{};
794}
795
796} // namespace event
#define assert(condition)
Definition: debug.h:74
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
void execute(sys::state &state, dcon::effect_key key, int32_t primary, int32_t this_slot, int32_t from_slot, uint32_t r_lo, uint32_t r_hi)
Definition: effects.cpp:5361
Definition: events.cpp:8
void take_option(sys::state &state, pending_human_n_event const &e, uint8_t opt)
Definition: events.cpp:14
slot_type
Definition: events.hpp:11
void update_future_events(sys::state &state)
Definition: events.cpp:473
void trigger_national_event(sys::state &state, dcon::national_event_id e, dcon::nation_id n, uint32_t r_lo, uint32_t r_hi, int32_t primary_slot, slot_type pt, int32_t from_slot, slot_type ft)
Definition: events.cpp:109
void fire_fixed_event(sys::state &state, std::vector< nations::fixed_event > const &v, int32_t primary_slot, slot_type pt, dcon::nation_id this_slot, int32_t from_slot, slot_type ft)
Definition: events.cpp:709
dcon::issue_id get_election_event_issue(sys::state &state, dcon::national_event_id e)
Definition: events.cpp:787
bool would_be_duplicate_instance(sys::state &state, dcon::national_event_id e, dcon::nation_id n, sys::date date)
Definition: events.cpp:459
void update_events(sys::state &state)
Definition: events.cpp:517
void trigger_provincial_event(sys::state &state, dcon::provincial_event_id e, dcon::province_id p, uint32_t r_hi, uint32_t r_lo, int32_t from_slot, slot_type ft)
Definition: events.cpp:295
bool event_has_options(sys::state &state, T id)
Definition: events.cpp:98
bool is_valid_option(sys::event_option const &opt)
Definition: events.cpp:10
void post(sys::state &state, message &&m)
uint64_t get_random(sys::state const &state, uint32_t value_in)
Definition: prng.cpp:8
constexpr int32_t max_event_options
Definition: constants.hpp:562
void add_line_break_to_layout_box(sys::state &state, layout_base &dest, layout_box &box)
Definition: text.cpp:1147
void add_to_layout_box(sys::state &state, layout_base &dest, layout_box &box, embedded_flag ico)
Definition: text.cpp:1165
layout_box open_layout_box(layout_base &dest, int32_t indent)
Definition: text.cpp:1799
ankerl::unordered_dense::map< uint32_t, substitution > substitution_map
Definition: text.hpp:794
void close_layout_box(columnar_layout &dest, layout_box &box)
Definition: text.cpp:1807
int32_t to_generic(dcon::province_id v)
Definition: triggers.hpp:12
dcon::province_id to_prov(int32_t v)
Definition: triggers.hpp:88
bool evaluate(sys::state &state, dcon::trigger_key key, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5810
float evaluate_multiplicative_modifier(sys::state &state, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5727
void populate_event_submap(sys::state &state, text::substitution_map &sub, std::variant< event::pending_human_n_event, event::pending_human_f_n_event, event::pending_human_p_event, event::pending_human_f_p_event > const &phe) noexcept
Definition: gui_event.cpp:12
T select(bool v, T a, T b)
bool compress_mask(bool v)
uint uint32_t
uchar uint8_t
bool operator==(event_nation_pair const &other) const noexcept
Definition: events.cpp:440
bool operator<(event_nation_pair const &other) const noexcept
Definition: events.cpp:443
dcon::nation_id n
Definition: events.cpp:437
dcon::free_national_event_id e
Definition: events.cpp:438
bool operator<(event_prov_pair const &other) const noexcept
Definition: events.cpp:454
bool operator==(event_prov_pair const &other) const noexcept
Definition: events.cpp:451
dcon::free_provincial_event_id e
Definition: events.cpp:449
dcon::province_id p
Definition: events.cpp:448
dcon::national_event_id e
Definition: events.cpp:705
dcon::provincial_event_id e
Definition: events.cpp:754
dcon::free_national_event_id e
Definition: events.hpp:38
dcon::province_id p
Definition: events.hpp:73
dcon::free_provincial_event_id e
Definition: events.hpp:72
dcon::national_event_id e
Definition: events.hpp:19
dcon::province_id p
Definition: events.hpp:55
dcon::provincial_event_id e
Definition: events.hpp:54