Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a suffocation gui overlay as a module - ticks left until death #1174

Merged
merged 9 commits into from
Jul 3, 2024
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Template for new versions:
## New Features
- `buildingplan`: dimension tooltip is now displayed for constructions and buildings that are designated over an area, like bridges and farm plots
- `gui/notify`: new notification type: injured citizens; click to zoom to injured units; also displays a warning if your hospital is not functional (or if you have no hospital)
- `gui/notify`: new notification type: drowning and suffocation progress bars for adventure mode
- `prioritize`: new info panel on under-construction buildings showing if the construction job has been taken and by whom. click to zoom to builder; toggle high priority status for job if it's not yet taken and you need it to be built ASAP
- `gui/pathable`: new "Depot" mode that shows whether wagons can path to your trade depot

Expand Down
6 changes: 6 additions & 0 deletions gui/notify.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ NotifyOverlay = defclass(NotifyOverlay, overlay.OverlayWidget)
NotifyOverlay.ATTRS{
default_enabled=true,
frame={w=30, h=LIST_MAX_HEIGHT+2},
overlay_onupdate_max_freq_seconds=5,
}

function NotifyOverlay:init()
Expand Down Expand Up @@ -64,6 +65,11 @@ end
function NotifyOverlay:overlay_onupdate()
local choices = {}
local is_adv = dfhack.world.isAdventureMode()
if is_adv then
self.overlay_onupdate_max_freq_seconds=0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this runs on every call to plugin_onupdate, which is way too often. is 5 seconds (or even the default 10) too slow for adventure mode?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moreover, the same notification overlay will never be in both dwarfmode and adventure mode. mode-specific logic should be in the specialized subclasses below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno how to refactor this because something as important as your suffocation bar needs to be delivered to the player as swiftly as possible. It's especially relevant for swimming.

Perhaps it should only be updated every tick? However there's no existing logic allowing it to be updated every tick currently.

Also, what specialized subclasses do you mean? They can't affect the frequency of updating of the overlay, can they?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what specialized subclasses do you mean?

I meant DwarfNotifyOverlay and AdvNotifyOverlay below, but I think this will take some more work in the framework

For now, could you revert changes to this file and instead set critical=true on the two notification types in notifications.lua?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else
self.overlay_onupdate_max_freq_seconds=5
end
for _, notification in ipairs(notifications.NOTIFICATIONS_BY_IDX) do
if not notifications.config.data[notification.name].enabled then goto continue end
local fn = get_fn(notification, is_adv)
Expand Down
87 changes: 87 additions & 0 deletions internal/notify/notifications.lua
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,79 @@ local function get_stranded_message()
end
end

local function get_blood()
return dfhack.world.getAdventurer().body.blood_count
end

local function get_max_blood()
return dfhack.world.getAdventurer().body.blood_max
end

local function get_max_breath()
local adventurer = dfhack.world.getAdventurer()
local toughness = dfhack.units.getPhysicalAttrValue(adventurer, df.physical_attribute_type.TOUGHNESS)
local endurance = dfhack.units.getPhysicalAttrValue(adventurer, df.physical_attribute_type.ENDURANCE)
local base_ticks = 200

return math.floor((endurance + toughness) / 4) + base_ticks
end

local function get_breath()
return get_max_breath() - dfhack.world.getAdventurer().counters.suffocation
end

local function get_suffocation_message()
if get_breath() < get_max_breath() then
local label_text = {}
local suffocation_pen = COLOR_LIGHTCYAN
-- if self.blink then
-- suffocation_pen = COLOR_CYAN
-- end
table.insert(label_text, {text = "Suffocating!", pen = suffocation_pen, width = 14})

local bar_width = 16
local percentage = get_breath() / get_max_breath()
local barstop = math.floor((bar_width * percentage) + 0.5)
for idx = 0, bar_width-1 do
local color = COLOR_LIGHTCYAN
local char = 219
if idx >= barstop then
-- offset it to the hollow graphic
color = COLOR_DARKGRAY
char = 177
end
table.insert(label_text, { width = 1, tile={ch=char, fg=color}})
end
return label_text
end
end

local function get_bleeding_message()
if get_blood() < get_max_blood() then
local label_text = {}
local bloodloss_pen = COLOR_RED
-- if self.blink then
-- bloodloss_pen = COLOR_LIGHTRED
-- end
table.insert(label_text, {text = "Bloodloss!", pen = bloodloss_pen, width = 14})

local margin = 14
local percentage = get_blood() / get_max_blood()
local barstop = math.floor((margin * percentage) + 0.5)
for idx = 0, margin-1 do
local color = COLOR_RED
local char = 219
if idx >= barstop then
-- offset it to the hollow graphic
color = COLOR_DARKGRAY
char = 177
end
table.insert(label_text, { width = 1, tile={ch=char, fg=color}})
end
myk002 marked this conversation as resolved.
Show resolved Hide resolved
return label_text
end
end

-- the order of this list controls the order the notifications will appear in the overlay
NOTIFICATIONS_BY_IDX = {
{
Expand Down Expand Up @@ -442,6 +515,20 @@ NOTIFICATIONS_BY_IDX = {
dwarf_fn=curry(injured_units, for_injured, 'injured citizen'),
on_click=curry(zoom_to_next, for_injured),
},
{
name='suffocation_adv',
desc='Shows a suffocation bar when you are drowning or breathless.',
default=true,
adv_fn=get_suffocation_message,
on_click=nil,
},
{
name='bleeding_adv',
desc='Shows a bleeding bar when you are losing blood.',
default=true,
adv_fn=get_bleeding_message,
on_click=nil,
},
}

NOTIFICATIONS_BY_NAME = {}
Expand Down