|
7 | 7 | #include <LuaWrapper.h> |
8 | 8 | #include <modules/Maps.h> |
9 | 9 | #include <df/job.h> |
| 10 | +#include <df/unit.h> |
10 | 11 |
|
11 | 12 | #include <cinttypes> |
12 | 13 | #include <unordered_set> |
13 | 14 | #include <random> |
| 15 | +#include <df/general_ref.h> |
14 | 16 |
|
15 | 17 | #define Coord(id) (id).x][(id).y |
16 | 18 | #define COORD "%" PRIi16 ",%" PRIi16 ",%" PRIi16 |
@@ -94,7 +96,10 @@ inline bool is_dig_job(const df::job* job) { |
94 | 96 | } |
95 | 97 |
|
96 | 98 | inline bool is_channel_job(const df::job* job) { |
97 | | - return job && (job->job_type == df::job_type::DigChannel); |
| 99 | + return job |
| 100 | + && job->id >= 0 |
| 101 | + && (job->job_type == df::job_type::DigChannel) |
| 102 | + && Maps::isValidTilePos(job->pos); |
98 | 103 | } |
99 | 104 |
|
100 | 105 | inline bool is_group_job(const ChannelGroups &groups, const df::job* job) { |
@@ -150,7 +155,8 @@ inline bool is_safe_to_dig_down(const df::coord &map_pos) { |
150 | 155 | // todo: remove? this is probably not useful.. and seems like the only considerable difference to is_safe_fall (aside from where each stops looking) |
151 | 156 | // the starting tile is open space, that's obviously not safe |
152 | 157 | return false; |
153 | | - } else if (!DFHack::isOpenTerrain(type)) { |
| 158 | + } |
| 159 | + if (!DFHack::isOpenTerrain(type)) { |
154 | 160 | // a tile after the first one is not open space |
155 | 161 | return true; |
156 | 162 | } |
@@ -185,21 +191,42 @@ inline bool has_any_groups_above(const ChannelGroups &groups, const Group &group |
185 | 191 | return false; |
186 | 192 | } |
187 | 193 |
|
| 194 | +inline int remove_worker(df::job* job) { |
| 195 | + df::unit* worker = Job::getWorker(job); |
| 196 | + if unlikely(!worker) return 0; |
| 197 | + auto R = std::erase_if(job->general_refs, [](df::general_ref* ref) { |
| 198 | + return ref->getType() == general_ref_type::UNIT_WORKER; |
| 199 | + }); |
| 200 | + if likely(R) { |
| 201 | + worker->job.current_job = nullptr; |
| 202 | + } |
| 203 | + return R; |
| 204 | +} |
| 205 | + |
188 | 206 | inline void cancel_job(df::job* job) { |
189 | 207 | if (job) { |
| 208 | + if (job->id < 0) { |
| 209 | + // seems like the event manager maybe gave us a fubar event |
| 210 | + Job::removePostings(job, true); |
| 211 | + return; |
| 212 | + } |
190 | 213 | const df::coord &pos = job->pos; |
191 | 214 | df::map_block* job_block = Maps::getTileBlock(pos); |
| 215 | + if (!job_block) { |
| 216 | + INFO(jobs).print("we dun fukked it"); |
| 217 | + return; |
| 218 | + } |
192 | 219 | uint16_t x, y; |
193 | 220 | x = pos.x % 16; |
194 | 221 | y = pos.y % 16; |
195 | | - df::tile_designation &designation = job_block->designation[x][y]; |
196 | 222 | auto type = job->job_type; |
197 | 223 | ChannelManager::Get().jobs.erase(pos); |
198 | 224 | Job::removeWorker(job); |
199 | 225 | Job::removePostings(job, true); |
200 | 226 | Job::removeJob(job); |
201 | 227 | job_block->flags.bits.designated = true; |
202 | 228 | job_block->occupancy[x][y].bits.dig_marked = true; |
| 229 | + df::tile_designation &designation = job_block->designation[x][y]; |
203 | 230 | switch (type) { |
204 | 231 | case job_type::Dig: |
205 | 232 | designation.bits.dig = df::tile_dig_designation::Default; |
@@ -227,8 +254,12 @@ inline void cancel_job(df::job* job) { |
227 | 254 | } |
228 | 255 |
|
229 | 256 | inline void cancel_job(const df::coord &map_pos) { |
230 | | - cancel_job(ChannelManager::Get().jobs.find_job(map_pos)); |
231 | | - ChannelManager::Get().jobs.erase(map_pos); |
| 257 | + if (const auto job = ChannelManager::Get().jobs.find_job(map_pos)) { |
| 258 | + cancel_job(job); |
| 259 | + ChannelManager::Get().jobs.erase(map_pos); |
| 260 | + } else { |
| 261 | + INFO(jobs).print("Cannot cancel the job at (" COORD "). It no longer exists as a job, it likely finished before we could cancel.\n", COORDARGS(map_pos)); |
| 262 | + } |
232 | 263 | } |
233 | 264 |
|
234 | 265 | // executes dig designations for the specified tile coordinates |
|
0 commit comments