Skip to content

Commit

Permalink
feat: Event triggers
Browse files Browse the repository at this point in the history
Added event trigger for building caught fire
Added event trigger for building collapse poor maintenance
  • Loading branch information
UberWaffe committed Jan 15, 2025
1 parent 821f15d commit d77ee79
Show file tree
Hide file tree
Showing 33 changed files with 348 additions and 125 deletions.
3 changes: 3 additions & 0 deletions src/building/construction.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "map/tiles.h"
#include "map/water.h"
#include "map/water_supply.h"
#include "scenario/scenario_events_controller.h"

#define MAX_CYCLE_SIZE 10

Expand Down Expand Up @@ -661,6 +662,8 @@ void building_construction_start(int x, int y, int grid_offset)
}
if (!can_start) {
building_construction_cancel();
} else {
scenario_events_full_process(EVENT_TRIGGER_BUILDING_PLACED_BY_PLAYER, 1, data.type);
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/building/construction_clear.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "map/routing_terrain.h"
#include "map/terrain.h"
#include "map/tiles.h"
#include "scenario/scenario_events_controller.h"
#include "translation/translation.h"
#include "window/popup_dialog.h"

Expand All @@ -30,6 +31,12 @@ static struct {
int monument_confirmed;
} confirm;

static void event_process_clearing(int building_type)
{
scenario_events_full_process(EVENT_TRIGGER_BUILDING_CLEARED_BY_PLAYER, 1, building_type);
scenario_events_full_process(EVENT_TRIGGER_BUILDING_DESTROYED_BY_ANYTHING, 1, building_type);
}

static building *get_deletable_building(int grid_offset)
{
int building_id = map_building_at(grid_offset);
Expand Down Expand Up @@ -144,10 +151,12 @@ static int clear_land_confirmed(int measure_only, int x_start, int y_start, int
game_undo_add_building(space);
space->state = BUILDING_STATE_DELETED_BY_PLAYER;
}
event_process_clearing(b->type);
} else if (map_terrain_is(grid_offset, TERRAIN_AQUEDUCT)) {
map_terrain_remove(grid_offset, TERRAIN_CLEARABLE & ~TERRAIN_HIGHWAY);
items_placed++;
map_aqueduct_remove(grid_offset);
event_process_clearing(BUILDING_AQUEDUCT);
} else if (map_terrain_is(grid_offset, TERRAIN_WATER)) {
if (!measure_only && map_bridge_count_figures(grid_offset) > 0) {
city_warning_show(WARNING_PEOPLE_ON_BRIDGE, NEW_WARNING_SLOT);
Expand All @@ -159,8 +168,17 @@ static int clear_land_confirmed(int measure_only, int x_start, int y_start, int
int next_highways_removed = map_tiles_clear_highway(grid_offset, measure_only);
highways_removed += next_highways_removed;
items_placed += next_highways_removed;
event_process_clearing(BUILDING_HIGHWAY);
} else if (map_terrain_is(grid_offset, TERRAIN_NOT_CLEAR)) {
if (map_terrain_is(grid_offset, TERRAIN_ROAD | TERRAIN_GARDEN)) {
int is_road = map_terrain_is(grid_offset, TERRAIN_ROAD);
int is_garden = map_terrain_is(grid_offset, TERRAIN_GARDEN);
if (is_road) {
event_process_clearing(BUILDING_ROAD);
}
if (is_garden) {
event_process_clearing(BUILDING_GARDENS);
}
if (is_road || is_garden) {
map_property_clear_plaza_earthquake_or_overgrown_garden(grid_offset);
}
map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
Expand Down
19 changes: 19 additions & 0 deletions src/building/destruction.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@
#include "map/routing_terrain.h"
#include "map/terrain.h"
#include "map/tiles.h"
#include "scenario/scenario_events_controller.h"
#include "sound/effect.h"

#include <string.h>

static void event_process_destruction(event_trigger trigger, int building_type)
{
scenario_events_full_process(trigger, 1, building_type);
scenario_events_full_process(EVENT_TRIGGER_BUILDING_DESTROYED_BY_ANYTHING, 1, building_type);
}

static void destroy_on_fire(building *b, int plagued)
{
game_undo_disable();
Expand Down Expand Up @@ -140,22 +147,31 @@ void building_destroy_by_collapse(building *b)
destroy_linked_parts(b, 0, 0);
}

void building_destroy_by_poor_maintenance(building *b)
{
building_destroy_by_collapse(b);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_POOR_MAINTENANCE, b->type);
}

void building_destroy_by_fire(building *b)
{
destroy_on_fire(b, 0);
destroy_linked_parts(b, 1, 0);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_FIRE, b->type);
}

void building_destroy_by_plague(building *b)
{
destroy_on_fire(b, 1);
destroy_linked_parts(b, 1, 1);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_DISEASE, b->type);
}

void building_destroy_by_rioter(building *b)
{
destroy_on_fire(b, 0);
destroy_linked_parts(b, 1, 0);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_COMBAT, b->type);
}

int building_destroy_first_of_type(building_type type)
Expand Down Expand Up @@ -210,16 +226,19 @@ void building_destroy_by_enemy(int x, int y, int grid_offset)
if (b->state == BUILDING_STATE_IN_USE || b->state == BUILDING_STATE_MOTHBALLED) {
city_ratings_peace_building_destroyed(b->type);
building_destroy_by_collapse(b);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_COMBAT, b->type);
}
} else {
if (map_terrain_is(grid_offset, TERRAIN_WALL)) {
figure_kill_tower_sentries_at(x, y);
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_COMBAT, BUILDING_WALL);
}
if (map_terrain_is(grid_offset, TERRAIN_GARDEN)) {
map_terrain_remove(grid_offset, TERRAIN_CLEARABLE);
map_tiles_update_region_empty_land(x, y, x, y);
map_property_clear_plaza_earthquake_or_overgrown_garden(grid_offset);
map_tiles_update_all_gardens();
event_process_destruction(EVENT_TRIGGER_BUILDING_DESTROYED_BY_COMBAT, BUILDING_GARDENS);
} else {
map_building_tiles_set_rubble(0, x, y, 1);
}
Expand Down
2 changes: 2 additions & 0 deletions src/building/destruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

void building_destroy_by_collapse(building *b);

void building_destroy_by_poor_maintenance(building *b);

void building_destroy_by_fire(building *b);

void building_destroy_by_plague(building *b);
Expand Down
2 changes: 1 addition & 1 deletion src/building/maintenance.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ static void collapse_building(building *b)
}

game_undo_disable();
building_destroy_by_collapse(b);
building_destroy_by_poor_maintenance(b);
}

static void fire_building(building *b)
Expand Down
6 changes: 4 additions & 2 deletions src/game/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ static int start_scenario(const uint8_t *scenario_name, const char *scenario_fil

if (!is_save_game) {
scenario_events_init();
scenario_events_process_all();
// Process month start events, since the first day of a new scenario does not trigger them
scenario_events_process_by_trigger_type(EVENT_TRIGGER_MONTH_START);
}
building_menu_update();
city_message_init_scenario();
Expand Down Expand Up @@ -405,7 +406,8 @@ int game_file_start_scenario_from_buffer(uint8_t *data, int length, int is_save_

if (!is_save_game) {
scenario_events_init();
scenario_events_process_all();
// Process month start events, since the first day of a new scenario does not trigger them
scenario_events_process_by_trigger_type(EVENT_TRIGGER_MONTH_START);
}
building_menu_update();
city_message_init_scenario();
Expand Down
4 changes: 2 additions & 2 deletions src/game/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "building/industry.h"
#include "building/lighthouse.h"
#include "building/maintenance.h"
#include "building/type.h"
#include "building/warehouse.h"
#include "city/buildings.h"
#include "city/culture.h"
Expand Down Expand Up @@ -115,8 +116,7 @@ static void advance_month(void)
city_games_decrement_month_counts();
city_gods_update_blessings();
tutorial_on_month_tick();
scenario_events_progress_paused(1);
scenario_events_process_all();
scenario_events_full_process(EVENT_TRIGGER_MONTH_START, 1, BUILDING_NONE);
if (setting_monthly_autosave()) {
game_file_write_saved_game(dir_append_location("autosave.svx", PATH_LOCATION_SAVEGAME));
}
Expand Down
2 changes: 2 additions & 0 deletions src/scenario/condition_types/condition_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ int scenario_condition_type_is_met(scenario_condition_t *condition)
return scenario_condition_type_building_count_area_met(condition);
case CONDITION_TYPE_CITY_POPULATION:
return scenario_condition_type_city_population_met(condition);
case CONDITION_TYPE_CONTEXT_BUILDING_TYPE:
return scenario_condition_type_context_building_type_met(condition);
case CONDITION_TYPE_COUNT_OWN_TROOPS:
return scenario_condition_type_count_own_troops_met(condition);
case CONDITION_TYPE_CUSTOM_VARIABLE_CHECK:
Expand Down
13 changes: 13 additions & 0 deletions src/scenario/condition_types/condition_types.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "map/grid.h"
#include "scenario/request.h"
#include "scenario/scenario.h"
#include "scenario/scenario_events_controller.h"
#include "scenario/condition_types/comparison_helper.h"

int scenario_condition_type_building_count_active_met(const scenario_condition_t *condition)
Expand Down Expand Up @@ -210,6 +211,18 @@ int scenario_condition_type_city_population_met(const scenario_condition_t *cond
return comparison_helper_compare_values(comparison, population_value_to_use, value);
}

int scenario_condition_type_context_building_type_met(const scenario_condition_t *condition)
{
int building_type = condition->parameter1;

scenario_event_context_t *context = scenario_events_get_context();
if (!context) {
return 0;
}

return (building_type == BUILDING_ANY) || (building_type == context->related_building_type);
}

int scenario_condition_type_count_own_troops_met(const scenario_condition_t *condition)
{
int comparison = condition->parameter1;
Expand Down
2 changes: 2 additions & 0 deletions src/scenario/condition_types/condition_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ int scenario_condition_type_city_population_met(const scenario_condition_t *cond

int scenario_condition_type_count_own_troops_met(const scenario_condition_t *condition);

int scenario_condition_type_context_building_type_met(const scenario_condition_t *condition);

int scenario_condition_type_custom_variable_check_met(const scenario_condition_t *condition);

int scenario_condition_type_difficulty_met(const scenario_condition_t *condition);
Expand Down
36 changes: 21 additions & 15 deletions src/scenario/scenario_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,28 @@ void scenario_event_save_state(buffer *buf, scenario_event_t *event)

buffer_write_i32(buf, event->id);
buffer_write_i16(buf, event->state);
buffer_write_i32(buf, event->repeat_months_min);
buffer_write_i32(buf, event->repeat_months_max);
buffer_write_i32(buf, event->months_until_active);
buffer_write_i16(buf, event->trigger);
buffer_write_i32(buf, event->repeat_triggers_min);
buffer_write_i32(buf, event->repeat_triggers_max);
buffer_write_i32(buf, event->triggers_until_active);
buffer_write_i32(buf, event->max_number_of_repeats);
buffer_write_i32(buf, event->execution_count);
buffer_write_i16(buf, event->conditions.size);
buffer_write_i16(buf, event->actions.size);
}

void scenario_event_load_state(buffer *buf, scenario_event_t *event)
void scenario_event_load_state(buffer *buf, scenario_event_t *event, int saved_version, int current_version)
{
int saved_id = buffer_read_i32(buf);
event->state = buffer_read_i16(buf);
event->repeat_months_min = buffer_read_i32(buf);
event->repeat_months_max = buffer_read_i32(buf);
event->months_until_active = buffer_read_i32(buf);
if (saved_version >= SCENARIO_EVENTS_VERSION_TRIGGERS) {
event->trigger = buffer_read_i16(buf);
} else {
event->trigger = EVENT_TRIGGER_MONTH_START;
}
event->repeat_triggers_min = buffer_read_i32(buf);
event->repeat_triggers_max = buffer_read_i32(buf);
event->triggers_until_active = buffer_read_i32(buf);
event->max_number_of_repeats = buffer_read_i32(buf);
event->execution_count = buffer_read_i32(buf);
int conditions_count = buffer_read_i16(buf);
Expand Down Expand Up @@ -136,7 +142,7 @@ void scenario_event_initialize_new(scenario_event_t *event, int position)

int scenario_event_can_repeat(scenario_event_t *event)
{
return (event->repeat_months_min > 0) && (event->repeat_months_max >= event->repeat_months_min) &&
return (event->repeat_triggers_min > 0) && (event->repeat_triggers_max >= event->repeat_triggers_min) &&
((event->execution_count < event->max_number_of_repeats) || (event->max_number_of_repeats <= 0));
}

Expand All @@ -159,19 +165,19 @@ int scenario_event_all_conditions_met(scenario_event_t *event)
return 1;
}

int scenario_event_decrease_pause_time(scenario_event_t *event, int months_passed)
int scenario_event_decrease_pause_count(scenario_event_t *event, int count)
{
if (event->state != EVENT_STATE_PAUSED) {
return 0;
}

if (event->months_until_active > 0) {
event->months_until_active -= months_passed;
if (event->triggers_until_active > 0) {
event->triggers_until_active -= count;
}
if (event->months_until_active < 0) {
event->months_until_active = 0;
if (event->triggers_until_active < 0) {
event->triggers_until_active = 0;
}
if (event->months_until_active == 0) {
if (event->triggers_until_active == 0) {
event->state = EVENT_STATE_ACTIVE;
}
return 1;
Expand All @@ -185,7 +191,7 @@ int scenario_event_conditional_execute(scenario_event_t *event)
if (scenario_event_can_repeat(event)) {
scenario_event_init(event);
event->state = EVENT_STATE_PAUSED;
event->months_until_active = random_between_from_stdlib(event->repeat_months_min, event->repeat_months_max);
event->triggers_until_active = random_between_from_stdlib(event->repeat_triggers_min, event->repeat_triggers_max);
} else {
event->state = EVENT_STATE_DISABLED;
}
Expand Down
5 changes: 3 additions & 2 deletions src/scenario/scenario_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
#define SCENARIO_EVENT_H

#include "core/buffer.h"
#include "scenario/scenario_events_controller.h"
#include "scenario/scenario_event_data.h"

void scenario_event_init(scenario_event_t *event);

void scenario_event_save_state(buffer *buf, scenario_event_t *event);
void scenario_event_load_state(buffer *buf, scenario_event_t *event);
void scenario_event_load_state(buffer *buf, scenario_event_t *event, int saved_version, int current_version);
scenario_condition_t *scenario_event_get_condition(scenario_event_t *event, int id);
scenario_condition_t *scenario_event_condition_create(scenario_event_t *event, int type);
void scenario_event_link_condition(scenario_event_t *event, scenario_condition_t *condition);
Expand All @@ -20,7 +21,7 @@ void scenario_event_initialize_new(scenario_event_t *event, int position);
int scenario_event_can_repeat(scenario_event_t *event);
int scenario_event_all_conditions_met(scenario_event_t *event);

int scenario_event_decrease_pause_time(scenario_event_t *event, int months_passed);
int scenario_event_decrease_pause_count(scenario_event_t *event, int count);
int scenario_event_conditional_execute(scenario_event_t *event);
int scenario_event_execute(scenario_event_t *event);
int scenario_event_uses_custom_variable(const scenario_event_t *event, int custom_variable_id);
Expand Down
21 changes: 18 additions & 3 deletions src/scenario/scenario_event_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ typedef enum {
EVENT_STATE_DELETED = 4
} event_state;

typedef enum {
EVENT_TRIGGER_UNDEFINED = 0,
EVENT_TRIGGER_MONTH_START = 1,
EVENT_TRIGGER_BUILDING_DESTROYED_BY_FIRE = 2,
EVENT_TRIGGER_BUILDING_DESTROYED_BY_POOR_MAINTENANCE = 3,
EVENT_TRIGGER_BUILDING_DESTROYED_BY_COMBAT = 4,
EVENT_TRIGGER_BUILDING_CLEARED_BY_PLAYER = 5,
EVENT_TRIGGER_BUILDING_DESTROYED_BY_DISEASE = 6,
EVENT_TRIGGER_BUILDING_DESTROYED_BY_ANYTHING = 7,
EVENT_TRIGGER_BUILDING_PLACED_BY_PLAYER = 8,
EVENT_TRIGGER_MAX,
} event_trigger;

typedef enum {
CONDITION_TYPE_UNDEFINED = 0,
CONDITION_TYPE_TIME_PASSED = 1,
Expand All @@ -43,6 +56,7 @@ typedef enum {
CONDITION_TYPE_RESOURCE_STORED_COUNT = 22,
CONDITION_TYPE_RESOURCE_STORAGE_AVAILABLE = 23,
CONDITION_TYPE_BUILDING_COUNT_AREA = 24,
CONDITION_TYPE_CONTEXT_BUILDING_TYPE = 25,
CONDITION_TYPE_MAX,
// helper constants
CONDITION_TYPE_MIN = CONDITION_TYPE_TIME_PASSED,
Expand Down Expand Up @@ -131,11 +145,12 @@ typedef struct {
typedef struct {
int id;
event_state state;
int repeat_months_min;
int repeat_months_max;
event_trigger trigger;
int repeat_triggers_min;
int repeat_triggers_max;
int max_number_of_repeats;
int execution_count;
int months_until_active;
int triggers_until_active;
array(scenario_condition_t) conditions;
array(scenario_action_t) actions;
} scenario_event_t;
Expand Down
Loading

0 comments on commit d77ee79

Please sign in to comment.