Skip to content

Commit e56675d

Browse files
authored
Merge pull request #1214 from DFHack/myk_timestream
[timestream] more work on counters and activities
2 parents e8a1e6e + fb21e88 commit e56675d

File tree

1 file changed

+75
-47
lines changed

1 file changed

+75
-47
lines changed

timestream.lua

+75-47
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ local argparse = require('argparse')
55
local repeatutil = require("repeat-util")
66
local utils = require('utils')
77

8+
DEBUG = DEBUG or false
9+
810
------------------------------------
911
-- state management
1012

@@ -91,62 +93,71 @@ local function clamp_timeskip(timeskip)
9193
return math.min(timeskip, get_next_trigger_year_tick(next_tick)-next_tick)
9294
end
9395

94-
local function has_caste_flag(unit, flag)
95-
if unit.curse.rem_tags1[flag] then return false end
96-
if unit.curse.add_tags1[flag] then return true end
97-
return dfhack.units.casteFlagSet(unit.race, unit.caste, df.caste_raw_flags[flag])
96+
local function increment_counter(obj, counter_name, timeskip)
97+
if obj[counter_name] <= 0 then return end
98+
obj[counter_name] = obj[counter_name] + timeskip
99+
end
100+
101+
local function decrement_counter(obj, counter_name, timeskip)
102+
if obj[counter_name] <= 0 then return end
103+
obj[counter_name] = math.max(1, obj[counter_name] - timeskip)
104+
end
105+
106+
local function adjust_unit_counters(unit, timeskip)
107+
local c1 = unit.counters
108+
decrement_counter(c1, 'think_counter', timeskip)
109+
decrement_counter(c1, 'job_counter', timeskip)
110+
decrement_counter(c1, 'swap_counter', timeskip)
111+
decrement_counter(c1, 'winded', timeskip)
112+
decrement_counter(c1, 'stunned', timeskip)
113+
decrement_counter(c1, 'unconscious', timeskip)
114+
decrement_counter(c1, 'suffocation', timeskip)
115+
decrement_counter(c1, 'webbed', timeskip)
116+
decrement_counter(c1, 'soldier_mood_countdown', timeskip)
117+
decrement_counter(c1, 'pain', timeskip)
118+
decrement_counter(c1, 'nausea', timeskip)
119+
decrement_counter(c1, 'dizziness', timeskip)
120+
local c2 = unit.counters2
121+
decrement_counter(c2, 'paralysis', timeskip)
122+
decrement_counter(c2, 'numbness', timeskip)
123+
decrement_counter(c2, 'fever', timeskip)
124+
decrement_counter(c2, 'exhaustion', timeskip * 3)
125+
increment_counter(c2, 'hunger_timer', timeskip)
126+
increment_counter(c2, 'thirst_timer', timeskip)
127+
local job = unit.job.current_job
128+
if job and job.job_type == df.job_type.Rest then
129+
decrement_counter(c2, 'sleepiness_timer', timeskip * 200)
130+
elseif job and job.job_type == df.job_type.Sleep then
131+
decrement_counter(c2, 'sleepiness_timer', timeskip * 19)
132+
else
133+
increment_counter(c2, 'sleepiness_timer', timeskip)
134+
end
135+
decrement_counter(c2, 'stomach_content', timeskip * 5)
136+
decrement_counter(c2, 'stomach_food', timeskip * 5)
137+
decrement_counter(c2, 'vomit_timeout', timeskip)
138+
-- stored_fat wanders about based on other state; we can probably leave it alone
98139
end
99140

141+
-- unit needs appear to be incremented on season ticks, so we don't need to worry about those
100142
local function adjust_units(timeskip)
101143
for _, unit in ipairs(df.global.world.units.active) do
102144
if not dfhack.units.isActive(unit) then goto continue end
103-
if unit.sex == df.pronoun_type.she then
104-
if unit.pregnancy_timer > 0 then
105-
unit.pregnancy_timer = math.max(1, unit.pregnancy_timer - timeskip)
106-
end
107-
end
145+
decrement_counter(unit, 'pregnancy_timer', timeskip)
108146
dfhack.units.subtractGroupActionTimers(unit, timeskip, df.unit_action_type_group.All)
109-
local job = unit.job.current_job
110-
local c2 = unit.counters2
111-
if job and job.job_type == df.job_type.Rest then
112-
c2.sleepiness_timer = math.max(0, c2.sleepiness_timer - timeskip * 200)
113-
end
114-
if not dfhack.units.isCitizen(unit, true) then goto continue end
115-
if not has_caste_flag(unit, 'NO_EAT') then
116-
c2.hunger_timer = c2.hunger_timer + timeskip
117-
end
118-
if not has_caste_flag(unit, 'NO_DRINK') then
119-
c2.thirst_timer = c2.thirst_timer + timeskip
120-
end
121-
if not has_caste_flag(unit, 'NO_SLEEP') then
122-
if job and job.job_type == df.job_type.Sleep then
123-
c2.sleepiness_timer = math.max(0, c2.sleepiness_timer - timeskip * 19)
124-
else
125-
c2.sleepiness_timer = c2.sleepiness_timer + timeskip
126-
end
127-
end
128-
-- TODO: c2.stomach_content, c2.stomach_food, and c2.stored_fat
129-
-- TODO: needs
147+
if not dfhack.units.isOwnGroup(unit) then goto continue end
148+
adjust_unit_counters(unit, timeskip)
130149
::continue::
131150
end
132151
end
133152

134-
local function increment_counter(ev, counter_name, timeskip)
135-
if ev[counter_name] <= 0 then return end
136-
ev[counter_name] = ev[counter_name] + timeskip
137-
end
138-
139-
local function decrement_counter(ev, counter_name, timeskip)
140-
if ev[counter_name] <= 0 then return end
141-
ev[counter_name] = math.max(1, ev[counter_name] - timeskip)
142-
end
143-
153+
-- behavior ascertained from in-game observation
144154
local function adjust_activities(timeskip)
145155
for i, act in ipairs(df.global.world.activities.all) do
146156
for _, ev in ipairs(act.events) do
147157
if df.activity_event_training_sessionst:is_instance(ev) then
148-
-- noop
158+
-- no counters
149159
elseif df.activity_event_combat_trainingst:is_instance(ev) then
160+
-- has organize_counter at a non-zero value, but it doesn't seem to move
150161
elseif df.activity_event_skill_demonstrationst:is_instance(ev) then
151162
-- can be negative or positive, but always counts towards 0
152163
if ev.organize_counter < 0 then
@@ -156,46 +167,62 @@ local function adjust_activities(timeskip)
156167
end
157168
decrement_counter(ev, 'train_countdown', timeskip)
158169
elseif df.activity_event_fill_service_orderst:is_instance(ev) then
170+
-- no counters
159171
elseif df.activity_event_individual_skill_drillst:is_instance(ev) then
160172
-- only counts down on season ticks, nothing to do here
161173
elseif df.activity_event_sparringst:is_instance(ev) then
174+
decrement_counter(ev, 'countdown', timeskip * 2)
162175
elseif df.activity_event_ranged_practicest:is_instance(ev) then
176+
-- countdown appears to never move from 0
163177
decrement_counter(ev, 'countdown', timeskip)
164178
elseif df.activity_event_harassmentst:is_instance(ev) then
179+
-- TODO: counter behavior not yet analyzed
180+
-- print(i)
165181
elseif df.activity_event_encounterst:is_instance(ev) then
182+
-- TODO: counter behavior not yet analyzed
183+
-- print(i)
166184
elseif df.activity_event_reunionst:is_instance(ev) then
185+
-- TODO: counter behavior not yet analyzed
186+
-- print(i)
167187
elseif df.activity_event_conversationst:is_instance(ev) then
168188
increment_counter(ev, 'pause', timeskip)
169189
elseif df.activity_event_guardst:is_instance(ev) then
190+
-- no counters
170191
elseif df.activity_event_conflictst:is_instance(ev) then
171192
increment_counter(ev, 'inactivity_timer', timeskip)
172193
increment_counter(ev, 'attack_inactivity_timer', timeskip)
173194
increment_counter(ev, 'stop_fort_fights_timer', timeskip)
174195
elseif df.activity_event_prayerst:is_instance(ev) then
175196
decrement_counter(ev, 'timer', timeskip)
176197
elseif df.activity_event_researchst:is_instance(ev) then
177-
-- noop
198+
-- no counters
178199
elseif df.activity_event_playst:is_instance(ev) then
179200
increment_counter(ev, 'down_time_counter', timeskip)
180201
elseif df.activity_event_worshipst:is_instance(ev) then
181202
increment_counter(ev, 'down_time_counter', timeskip)
182203
elseif df.activity_event_socializest:is_instance(ev) then
183204
increment_counter(ev, 'down_time_counter', timeskip)
184205
elseif df.activity_event_ponder_topicst:is_instance(ev) then
206+
decrement_counter(ev, 'timer', timeskip)
185207
elseif df.activity_event_discuss_topicst:is_instance(ev) then
186208
decrement_counter(ev, 'timer', timeskip)
187209
elseif df.activity_event_teach_topicst:is_instance(ev) then
210+
decrement_counter(ev, 'time_left', timeskip)
188211
elseif df.activity_event_readst:is_instance(ev) then
189212
decrement_counter(ev, 'timer', timeskip)
190213
elseif df.activity_event_writest:is_instance(ev) then
191214
decrement_counter(ev, 'timer', timeskip)
192215
elseif df.activity_event_copy_written_contentst:is_instance(ev) then
216+
decrement_counter(ev, 'time_left', timeskip)
193217
elseif df.activity_event_make_believest:is_instance(ev) then
194218
decrement_counter(ev, 'time_left', timeskip)
195219
elseif df.activity_event_play_with_toyst:is_instance(ev) then
220+
decrement_counter(ev, 'time_left', timeskip)
196221
elseif df.activity_event_performancest:is_instance(ev) then
197222
increment_counter(ev, 'current_position', timeskip)
198223
elseif df.activity_event_store_objectst:is_instance(ev) then
224+
-- TODO: counter behavior not yet analyzed
225+
-- print(i)
199226
end
200227
end
201228
end
@@ -214,18 +241,19 @@ local function on_tick()
214241
-- add some jitter so we don't fall into a constant pattern
215242
-- this reduces the risk of repeatedly missing an unknown threshold
216243
-- also keeps the game from looking robotic at lower frame rates
217-
local jitter_category = math.random(1, 10)
218-
if jitter_category <= 1 then
244+
local jitter_strategy = math.random(1, 10)
245+
if jitter_strategy <= 1 then
219246
timeskip = math.random(0, timeskip)
220-
elseif jitter_category <= 3 then
247+
elseif jitter_strategy <= 3 then
221248
timeskip = math.random(math.max(0, timeskip-2), timeskip)
222-
elseif jitter_category <= 5 then
249+
elseif jitter_strategy <= 5 then
223250
timeskip = math.random(math.max(0, timeskip-4), timeskip)
224251
end
225252

226-
-- no need to let our deficit grow unbounded
253+
-- don't let our deficit grow unbounded if we can never catch up
227254
timeskip_deficit = math.min(desired_timeskip - timeskip, 100.0)
228255

256+
if DEBUG then print(('timeskip (%d, +%.2f)'):format(timeskip, timeskip_deficit)) end
229257
if timeskip <= 0 then return end
230258

231259
local desired_calendar_timeskip = (timeskip * state.settings.calendar_rate) + calendar_timeskip_deficit

0 commit comments

Comments
 (0)