diff --git a/src/building/building.c b/src/building/building.c index f6d34b5b28..c1df07ab04 100644 --- a/src/building/building.c +++ b/src/building/building.c @@ -278,6 +278,9 @@ void building_clear_related_data(building *b) city_buildings_remove_triumphal_arch(); building_menu_update(); } + if (building_monument_is_unfinished_monument(b)) { + building_monument_remove_all_deliveries(b->id); + } } building *building_restore_from_undo(building *to_restore) diff --git a/src/building/monument.c b/src/building/monument.c index 2f4521955d..ec53ad1020 100644 --- a/src/building/monument.c +++ b/src/building/monument.c @@ -477,18 +477,29 @@ void building_monument_initialize_deliveries(void) } } -void building_monument_add_delivery(int monument_id, int figure_id, int resource_id, int loads_no) +void building_monument_add_delivery(int monument_id, int figure_id, int resource_id, int num_loads) { monument_delivery *delivery; array_new_item(monument_deliveries, 0, delivery); if (!delivery) { - log_error("Failed to create a new monument delivery. The game maybe running out of memory", 0, 0); + log_error("Failed to create a new monument delivery. The game may be running out of memory", 0, 0); return; } delivery->destination_id = monument_id; delivery->walker_id = figure_id; delivery->resource = resource_id; - delivery->cartloads = loads_no; + delivery->cartloads = num_loads; +} + +int building_monument_has_delivery_for_worker(int figure_id) +{ + monument_delivery *delivery; + array_foreach(monument_deliveries, delivery) { + if (delivery->walker_id == figure_id && delivery->destination_id > 0) { + return 1; + } + } + return 0; } void building_monument_remove_delivery(int figure_id) @@ -502,6 +513,17 @@ void building_monument_remove_delivery(int figure_id) array_trim(monument_deliveries); } +void building_monument_remove_all_deliveries(int monument_id) +{ + monument_delivery *delivery; + array_foreach(monument_deliveries, delivery) { + if (delivery->destination_id == monument_id) { + delivery->destination_id = 0; + } + } + array_trim(monument_deliveries); +} + static int resource_in_delivery(int monument_id, int resource_id) { int resources = 0; diff --git a/src/building/monument.h b/src/building/monument.h index d1157445eb..81facdc307 100644 --- a/src/building/monument.h +++ b/src/building/monument.h @@ -43,7 +43,9 @@ int building_monument_has_required_resources_to_build(building_type type); int building_monument_resources_needed_for_monument_type(building_type type, int resource, int phase); int building_monument_resource_in_delivery(building *b, int resource_id); void building_monument_remove_delivery(int figure_id); -void building_monument_add_delivery(int monument_id, int figure_id, int resource_id, int loads_no); +void building_monument_add_delivery(int monument_id, int figure_id, int resource_id, int num_loads); +int building_monument_has_delivery_for_worker(int figure_id); +void building_monument_remove_all_deliveries(int monument_id); int building_monument_get_id(building_type type); int building_monument_upgraded(building_type type); int building_monument_module_type(building_type type); diff --git a/src/figure/action.c b/src/figure/action.c index 82a2838734..ab2746de17 100644 --- a/src/figure/action.c +++ b/src/figure/action.c @@ -103,7 +103,7 @@ static void (*figure_action_callbacks[])(figure *f) = { figure_hippodrome_horse_action, figure_workcamp_worker_action, figure_workcamp_slave_action, - figure_workcamp_engineer_action, + figure_workcamp_architect_action, figure_supplier_action, figure_delivery_boy_action, figure_supplier_action, diff --git a/src/figure/figure.c b/src/figure/figure.c index fe280a934c..ad6072bba7 100644 --- a/src/figure/figure.c +++ b/src/figure/figure.c @@ -1,6 +1,7 @@ #include "figure/figure.h" #include "building/building.h" +#include "building/monument.h" #include "core/array.h" #include "core/log.h" #include "city/emperor.h" @@ -169,6 +170,12 @@ void figure_delete(figure *f) } } break; + case FIGURE_CART_PUSHER: + case FIGURE_WORK_CAMP_ARCHITECT: + case FIGURE_WORK_CAMP_WORKER: + case FIGURE_WORK_CAMP_SLAVE: + building_monument_remove_delivery(f->id); + // intentional fallthrough default: if (f->building_id) { b->figure_id = 0; diff --git a/src/figuretype/cartpusher.c b/src/figuretype/cartpusher.c index 692ecd4251..33a808ba55 100644 --- a/src/figuretype/cartpusher.c +++ b/src/figuretype/cartpusher.c @@ -22,6 +22,7 @@ #include "map/terrain.h" #define NON_STORABLE_RESOURCE_CARTPUSHER_MAX_WAIT_TICKS 300 +#define VALID_MONUMENT_RECHECK_TICKS 60 static int cartpusher_carries_food(figure *f) { @@ -180,6 +181,7 @@ static void determine_cartpusher_destination(figure *f, building *b, int road_ne // Special priority for non-storable resource: monument under construction dst_building_id = building_monument_get_monument(f->x, f->y, b->output_resource_id, road_network_id, &dst); if (dst_building_id) { + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; set_destination(f, FIGURE_ACTION_239_CARTPUSHER_DELIVERING_TO_MONUMENT, dst_building_id, dst.x, dst.y); building_monument_add_delivery(dst_building_id, f->id, b->output_resource_id, 1); } else { @@ -404,6 +406,13 @@ void figure_cartpusher_action(figure *f) } break; case FIGURE_ACTION_239_CARTPUSHER_DELIVERING_TO_MONUMENT: + if (f->wait_ticks++ >= VALID_MONUMENT_RECHECK_TICKS) { + if (!building_monument_has_delivery_for_worker(f->id)) { + f->state = FIGURE_STATE_DEAD; + break; + } + f->wait_ticks = 0; + } set_cart_graphic(f, 1); figure_movement_move_ticks_with_percentage(f, 1, percentage_speed); if (f->direction == DIR_FIGURE_AT_DESTINATION) { @@ -462,6 +471,10 @@ void figure_cartpusher_action(figure *f) case FIGURE_ACTION_240_CARTPUSHER_AT_MONUMENT: f->wait_ticks++; if (f->wait_ticks > 5) { + if (!building_monument_has_delivery_for_worker(f->id)) { + f->state = FIGURE_STATE_DEAD; + break; + } building_monument_deliver_resource(building_get(f->destination_building_id), f->resource_id); building_monument_remove_delivery(f->id); f->action_state = FIGURE_ACTION_27_CARTPUSHER_RETURNING; @@ -501,9 +514,6 @@ void figure_cartpusher_action(figure *f) } } update_image(f); - if (f->state == FIGURE_STATE_DEAD) { - building_monument_remove_delivery(f->id); - } } static void determine_granaryman_destination(figure *f, int road_network_id, int remove_resources) diff --git a/src/figuretype/workcamp.c b/src/figuretype/workcamp.c index a184e4ae86..362579e47d 100644 --- a/src/figuretype/workcamp.c +++ b/src/figuretype/workcamp.c @@ -18,6 +18,8 @@ #include "map/figure.h" #include "map/grid.h" +#define VALID_MONUMENT_RECHECK_TICKS 60 + static int create_slave_workers(int leader_id, int first_figure_id) { figure *f = figure_get(first_figure_id); @@ -30,6 +32,7 @@ static int create_slave_workers(int leader_id, int first_figure_id) slave->destination_x = f->destination_x; slave->destination_y = f->destination_y; slave->action_state = FIGURE_ACTION_209_WORK_CAMP_SLAVE_FOLLOWING; + slave->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; building_monument_add_delivery(slave->destination_building_id, f->id, f->collecting_item_id, 1); return slave->id; } @@ -65,6 +68,17 @@ static int take_resource_from_warehouse(figure *f, int warehouse_id) return 1; } +static int has_valid_monument_destination(figure *f) +{ + if (f->wait_ticks++ >= VALID_MONUMENT_RECHECK_TICKS) { + if (!building_monument_has_delivery_for_worker(f->id)) { + return 0; + } + f->wait_ticks = 0; + } + return 1; +} + void figure_workcamp_worker_action(figure *f) { f->terrain_usage = TERRAIN_USAGE_ROADS_HIGHWAY; @@ -75,6 +89,7 @@ void figure_workcamp_worker_action(figure *f) if (b->state != BUILDING_STATE_IN_USE || b->figure_id != f->id) { f->state = FIGURE_STATE_DEAD; } + figure_image_increase_offset(f, 12); switch (f->action_state) { case FIGURE_ACTION_150_ATTACK: @@ -86,6 +101,7 @@ void figure_workcamp_worker_action(figure *f) case FIGURE_ACTION_203_WORK_CAMP_WORKER_CREATED: if (!building_monument_has_unfinished_monuments()) { f->state = FIGURE_STATE_DEAD; + break; } for (int resource = RESOURCE_MIN; resource < RESOURCE_MAX; resource++) { if (city_resource_is_stockpiled(resource) || !resource_is_storable(resource)) { @@ -103,6 +119,7 @@ void figure_workcamp_worker_action(figure *f) f->destination_building_id = warehouse_id; f->destination_x = dst.x; f->destination_y = dst.y; + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; f->action_state = FIGURE_ACTION_204_WORK_CAMP_WORKER_GETTING_RESOURCES; building *monument = building_get(monument_id); int resources_needed = monument->resources[resource] - building_monument_resource_in_delivery(monument, resource); @@ -116,9 +133,12 @@ void figure_workcamp_worker_action(figure *f) break; case FIGURE_ACTION_204_WORK_CAMP_WORKER_GETTING_RESOURCES: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } figure_movement_move_ticks(f, 1); if (f->direction == DIR_FIGURE_AT_DESTINATION) { - building_monument_remove_delivery(f->id); warehouse_id = f->destination_building_id; monument_id = building_monument_get_monument(b->x, b->y, f->collecting_item_id, b->road_network_id, &dst); f->action_state = FIGURE_ACTION_205_WORK_CAMP_WORKER_GOING_TO_MONUMENT; @@ -127,6 +147,7 @@ void figure_workcamp_worker_action(figure *f) f->destination_y = dst.y; f->previous_tile_x = f->x; f->previous_tile_y = f->y; + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; int figure_id = f->id; if (!monument_id) { f->state = FIGURE_STATE_DEAD; @@ -138,9 +159,15 @@ void figure_workcamp_worker_action(figure *f) f->state = FIGURE_STATE_DEAD; } break; + case FIGURE_ACTION_205_WORK_CAMP_WORKER_GOING_TO_MONUMENT: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } figure_movement_move_ticks(f, 1); if (f->direction == DIR_FIGURE_AT_DESTINATION || f->direction == DIR_FIGURE_LOST) { + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; f->action_state = FIGURE_ACTION_216_WORK_CAMP_WORKER_ENTERING_MONUMENT; building *monument = building_get(f->destination_building_id); if (!building_monument_access_point(monument, &dst)) { @@ -151,7 +178,12 @@ void figure_workcamp_worker_action(figure *f) figure_route_remove(f); } break; + case FIGURE_ACTION_216_WORK_CAMP_WORKER_ENTERING_MONUMENT: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } f->terrain_usage = TERRAIN_USAGE_ANY; f->use_cross_country = 1; f->dont_draw_elevated = 1; @@ -162,12 +194,10 @@ void figure_workcamp_worker_action(figure *f) figure_route_remove(f); } } + break; } figure_image_update(f, image_group(GROUP_FIGURE_PATRICIAN)); - if (f->state == FIGURE_STATE_DEAD) { - building_monument_remove_delivery(f->id); - } } void figure_workcamp_slave_action(figure *f) @@ -186,27 +216,39 @@ void figure_workcamp_slave_action(figure *f) figure_combat_handle_corpse(f); break; case FIGURE_ACTION_209_WORK_CAMP_SLAVE_FOLLOWING: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } if (f->leading_figure_id <= 0 || leader->action_state == FIGURE_ACTION_149_CORPSE) { f->state = FIGURE_STATE_DEAD; } else { if (leader->state == FIGURE_STATE_ALIVE) { if (leader->type == FIGURE_WORK_CAMP_WORKER || leader->type == FIGURE_WORK_CAMP_SLAVE) { figure_movement_follow_ticks(f, 1); - if (leader->action_state == FIGURE_ACTION_210_WORK_CAMP_SLAVE_GOING_TO_MONUMENT || leader->action_state == FIGURE_ACTION_216_WORK_CAMP_WORKER_ENTERING_MONUMENT) { + if (leader->action_state == FIGURE_ACTION_210_WORK_CAMP_SLAVE_GOING_TO_MONUMENT || + leader->action_state == FIGURE_ACTION_216_WORK_CAMP_WORKER_ENTERING_MONUMENT) { f->action_state = FIGURE_ACTION_210_WORK_CAMP_SLAVE_GOING_TO_MONUMENT; + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; } } else { f->state = FIGURE_STATE_DEAD; } } else { // leader arrived at the monument, continue on your own f->action_state = FIGURE_ACTION_210_WORK_CAMP_SLAVE_GOING_TO_MONUMENT; + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; } } if (leader->is_ghost && !leader->height_adjusted_ticks) { f->is_ghost = 1; } break; + case FIGURE_ACTION_210_WORK_CAMP_SLAVE_GOING_TO_MONUMENT: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } figure_movement_move_ticks(f, 1); if (f->direction == DIR_FIGURE_AT_DESTINATION || f->direction == DIR_FIGURE_LOST) { f->action_state = FIGURE_ACTION_211_WORK_CAMP_SLAVE_DELIVERING_RESOURCES; @@ -214,12 +256,18 @@ void figure_workcamp_slave_action(figure *f) if (!building_monument_access_point(monument, &dst)) { f->state = FIGURE_STATE_DEAD; } + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; figure_movement_set_cross_country_destination(f, dst.x, dst.y); } else if (f->direction == DIR_FIGURE_REROUTE) { figure_route_remove(f); } break; + case FIGURE_ACTION_211_WORK_CAMP_SLAVE_DELIVERING_RESOURCES: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } f->terrain_usage = TERRAIN_USAGE_ANY; f->use_cross_country = 1; f->dont_draw_elevated = 1; @@ -243,12 +291,9 @@ void figure_workcamp_slave_action(figure *f) f->image_id = assets_get_image_id("Walkers", "Slave NE 01") + dir * 12 + f->image_offset; } - if (f->state == FIGURE_STATE_DEAD) { - building_monument_remove_delivery(f->id); - } } -void figure_workcamp_engineer_action(figure *f) +void figure_workcamp_architect_action(figure *f) { f->terrain_usage = TERRAIN_USAGE_ROADS_HIGHWAY; building *b = building_get(f->building_id); @@ -274,9 +319,10 @@ void figure_workcamp_engineer_action(figure *f) f->destination_building_id = monument_id; f->destination_x = dst.x; f->destination_y = dst.y; - // Only send 1 engineer + // Only send 1 architect building_monument_add_delivery(f->destination_building_id, f->id, RESOURCE_NONE, 10); f->action_state = FIGURE_ACTION_207_WORK_CAMP_ARCHITECT_GOING_TO_MONUMENT; + f->wait_ticks = VALID_MONUMENT_RECHECK_TICKS; break; } else { f->state = FIGURE_STATE_DEAD; @@ -284,7 +330,12 @@ void figure_workcamp_engineer_action(figure *f) } figure_image_update(f, image_group(GROUP_FIGURE_ENGINEER)); break; + case FIGURE_ACTION_207_WORK_CAMP_ARCHITECT_GOING_TO_MONUMENT: + if (!has_valid_monument_destination(f)) { + f->state = FIGURE_STATE_DEAD; + break; + } figure_movement_move_ticks(f, 1); monument = building_get(f->destination_building_id); if (monument->state == BUILDING_STATE_UNUSED || !building_monument_access_point(monument, &dst) || @@ -326,7 +377,4 @@ void figure_workcamp_engineer_action(figure *f) } break; } - if (f->state == FIGURE_STATE_DEAD) { - building_monument_remove_delivery(f->id); - } } diff --git a/src/figuretype/workcamp.h b/src/figuretype/workcamp.h index f89f80d2c2..e10a658e62 100644 --- a/src/figuretype/workcamp.h +++ b/src/figuretype/workcamp.h @@ -5,13 +5,11 @@ #define CARTLOADS_PER_MONUMENT_DELIVERY 4 -void figure_workcamp_worker_action(figure* f); +void figure_workcamp_worker_action(figure *f); -void figure_workcamp_slave_action(figure* f); - -void figure_workcamp_engineer_action(figure* f); +void figure_workcamp_slave_action(figure *f); +void figure_workcamp_architect_action(figure *f); #endif // FIGURETYPE_WORKCAMP_H -