Skip to content

Commit c0b1bf8

Browse files
committed
Fix getplants "ripe" and "picked" logic
Added Splitmix64 RNG to Random module; not yet exposed from Lua, but that can be added later if deemed necessary.
1 parent 84791f1 commit c0b1bf8

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

docs/changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,15 @@ Template for new versions:
5757

5858
## Fixes
5959
- `getplants`: will no longer crash when faced with plants with growths that do not drop seeds when processed
60+
- `getplants`: use updated formula for calculating whether plant growths are ripe
61+
- `getplants`: fix logic for determining whether plant growths have been picked
6062

6163
## Misc Improvements
6264

6365
## Documentation
6466

6567
## API
68+
- ``Random`` module: added SplitmixRNG class, implements the Splitmix64 RNG used by Dwarf Fortress for "simple" randomness
6669

6770
## Lua
6871

library/include/modules/Random.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,37 @@ namespace Random
106106
extern template void DFHACK_IMPORT MersenneRNG::unitvector<double>(double *p, int size);
107107
#endif
108108

109+
// Standard Splitmix64 RNG, as used by Dwarf Fortress's "hash_rngst" class
110+
class SplitmixRNG
111+
{
112+
uint64_t state;
113+
114+
public:
115+
SplitmixRNG(uint64_t seed) {
116+
init(seed);
117+
}
118+
119+
void init(uint64_t seed) {
120+
state = seed;
121+
}
122+
123+
uint64_t next() {
124+
state += 0x9e3779b97f4a7c15;
125+
uint64_t z = state;
126+
z ^= z >> 30;
127+
z *= 0xbf58476d1ce4e5b9;
128+
z ^= z >> 27;
129+
z *= 0x94d049bb133111eb;
130+
z ^= z >> 31;
131+
return z;
132+
}
133+
134+
int32_t df_trandom(uint32_t max) {
135+
uint32_t val = next() >> 32;
136+
return (int32_t)(val % max);
137+
}
138+
};
139+
109140
/*
110141
* Classical Perlin noise function in template form.
111142
* http://mrl.nyu.edu/~perlin/doc/oscar.html#noise

plugins/getplants.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "modules/Designations.h"
66
#include "modules/Maps.h"
77
#include "modules/Materials.h"
8+
#include "modules/Random.h"
89

910
#include "df/map_block.h"
1011
#include "df/map_block_column.h"
@@ -211,32 +212,31 @@ selectability selectablePlant(color_ostream& out, const df::plant_raw* plant, bo
211212
}
212213

213214
// Formula for determination of the variance in plant growth maturation time, determined via disassembly.
214-
// The x and y parameters are in tiles relative to the embark.
215-
bool ripe(int32_t x, int32_t y, int32_t start, int32_t end) {
216-
int32_t time = (((435522653 - (((y + 3) * x + 5) * ((y + 7) * y * 400181475 + 289700012))) & 0x3FFFFFFF) % 2000 + *cur_year_tick) % 403200;
215+
// The coordinates are relative to the embark region.
216+
bool ripe(int32_t x, int32_t y, int32_t z, int32_t start, int32_t end) {
217+
DFHack::Random::SplitmixRNG rng((world->map.region_x * 48 + x) + (world->map.region_y * 48 + y) * 10000 + (world->map.region_z + z) * 100000000);
218+
int32_t time = (rng.df_trandom(2000) + *cur_year_tick) % 403200;
217219

218220
return time >= start && (end == -1 || time <= end);
219221
}
220222

221-
// Looks in the picked growths vector to see if a matching growth has been marked as picked.
222-
bool picked(const df::plant* plant, int32_t growth_subtype) {
223-
df::world_data* world_data = world->world_data;
224-
df::world_site* site = df::world_site::find(plotinfo->site_id);
225-
int32_t pos_x = site->global_min_x + plant->pos.x / 48;
226-
int32_t pos_y = site->global_min_y + plant->pos.y / 48;
227-
size_t id = pos_x + pos_y * 16 * world_data->world_width;
228-
df::world_object_data* object_data = df::world_object_data::find(id);
229-
if (!object_data) {
223+
// Looks in the local creation zone's picked growths vector to see if a matching growth has been marked as picked.
224+
bool picked(const df::plant* plant, int32_t growth_subtype, int32_t growth_density) {
225+
int32_t pos_x = plant->pos.x / 48 + world->map.region_x;
226+
int32_t pos_y = plant->pos.y / 48 + world->map.region_y;
227+
size_t cz_id = pos_x + pos_y * 16 * world->world_data->world_width;
228+
auto cz = df::world_object_data::find(cz_id);
229+
if (!cz) {
230230
return false;
231231
}
232-
df::map_block_column* column = world->map.map_block_columns[(plant->pos.x / 16) * world->map.x_count_block + (plant->pos.y / 16)];
233-
234-
for (size_t i = 0; i < object_data->picked_growths.x.size(); i++) {
235-
if (object_data->picked_growths.x[i] == plant->pos.x &&
236-
object_data->picked_growths.y[i] == plant->pos.y &&
237-
object_data->picked_growths.z[i] - column->z_base == plant->pos.z &&
238-
object_data->picked_growths.subtype[i] == growth_subtype &&
239-
object_data->picked_growths.year[i] == *cur_year) {
232+
233+
for (size_t i = 0; i < cz->picked_growths.x.size(); i++) {
234+
if (cz->picked_growths.x[i] == (plant->pos.x % 48) &&
235+
cz->picked_growths.y[i] == (plant->pos.y % 48) &&
236+
cz->picked_growths.z[i] == (plant->pos.z + world->map.region_z) &&
237+
cz->picked_growths.density[i] >= growth_density &&
238+
cz->picked_growths.subtype[i] == growth_subtype &&
239+
cz->picked_growths.year[i] == *cur_year) {
240240
return true;
241241
}
242242
}
@@ -310,8 +310,8 @@ bool designate(color_ostream& out, const df::plant* plant, bool farming) {
310310
}
311311

312312
if ((!farming || seedSource) &&
313-
ripe(plant->pos.x, plant->pos.y, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2) &&
314-
!picked(plant, i))
313+
ripe(plant->pos.x, plant->pos.y, plant->pos.z, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2) &&
314+
!picked(plant, i, plant_raw->growths[i]->density))
315315
return Designations::markPlant(plant);
316316
}
317317

0 commit comments

Comments
 (0)