Skip to content

Commit

Permalink
Try to fix slave workers going to a deleted monument
Browse files Browse the repository at this point in the history
  • Loading branch information
crudelios committed Aug 8, 2023
1 parent 205eead commit eef6572
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 26 deletions.
3 changes: 3 additions & 0 deletions src/building/building.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
28 changes: 25 additions & 3 deletions src/building/monument.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion src/building/monument.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/figure/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions src/figure/figure.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 13 additions & 3 deletions src/figuretype/cartpusher.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
74 changes: 61 additions & 13 deletions src/figuretype/workcamp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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)) {
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)) {
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -186,40 +216,58 @@ 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;
building *monument = building_get(f->destination_building_id);
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;
Expand All @@ -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);
Expand All @@ -274,17 +319,23 @@ 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;
}
}
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) ||
Expand Down Expand Up @@ -326,7 +377,4 @@ void figure_workcamp_engineer_action(figure *f)
}
break;
}
if (f->state == FIGURE_STATE_DEAD) {
building_monument_remove_delivery(f->id);
}
}
Loading

0 comments on commit eef6572

Please sign in to comment.