Skip to content

Fix/artefact container getters - #2130

Closed
mikhailRo wants to merge 40 commits into
OpenXRay:devfrom
mikhailRo:fix/artefact-container-getters
Closed

Fix/artefact container getters#2130
mikhailRo wants to merge 40 commits into
OpenXRay:devfrom
mikhailRo:fix/artefact-container-getters

Conversation

@mikhailRo

Copy link
Copy Markdown

No description provided.

abstrack and others added 30 commits July 27, 2026 10:06
…rgences

Squashed source patch set built up while porting the Dead Air Revolution 2 mod
(a Shadow of Chernobyl mod on a heavily modified proprietary engine) onto
stock OpenXRay. Full investigation history, root causes, and per-fix
build/verify notes are in HANDOFF-DeadAir-OpenXRay.md.

Highlights:
- Crash fixes: spatial-tree octant OOB on level load, A-Life registry THROW
  asserts on load/unload, ambient-sound R_ASSERT relaxation.
- Restored engine features Dead Air's original build had but stock OpenXRay
  lacks: full Torch scripting API, artefact dynamic-property setters,
  several missing script exports, render cvars for the dynamic post-process
  script (DOF/vibrance/lens/SSS/color-grade), native crash stack traces.
- Rendering: NaN postprocess constants causing load-time corruption (scramble
  + dim variants), spot-light cookie texture zeroing dynamic lighting.
- Data-vs-enum divergences between Dead Air's data-driven slot/state layout
  and OpenXRay's hardcoded enums (5 instances): HUD-state enum renumbering,
  duplicate key bindings (torch, night vision), inventory slot routing
  (grenades/pistols/binoculars), and backpack slot/class mismatch.
  Fixed by realigning enums or loose data to match, per-case, never both.
- UI/input: Escape key dialog-stacking/render-desync fixes, PDA update crash
  guard.

See HANDOFF-DeadAir-OpenXRay.md for the complete, numbered write-up (28
sections) of each bug: symptom, root cause, fix, and build/verify status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Port Dead Air Revolution 2 to OpenXRay: 28 fixes for engine/data dive…
The equip-slot condition indicators (progess_bar_sidearm,
progess_bar_backpack) are authored in actor_menu_16.xml but the
inventory_lists table in CUIActorMenu::InitializeUniversal never wired
them up via SetConditionIndicator, unlike every other single-item slot
(knife/pistol/automatic/outfit/helmet). CUIDragDropListEx::Update()
only refreshes m_condition_indicator when it's non-null, so these two
slots' bars stayed at their unset default (empty) while equipped, and
only looked correct again once the item returned to the ruck's grid
list, which uses the separate per-cell UICellItem condition bar path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix empty durability bar on backpack/sidearm equip slots
CActor::currentFOV() set the camera FOV directly to
pWeapon->GetZoomFactor() * 0.75, i.e. it treated the weapon's
ironsight/scope zoom_factor ltx value as an already-computed target
FOV in degrees. Dead Air's weapon configs use zoom_factor as a
divisor against the base FOV instead (base ironsight ~1.8, optical
scopes ~6-20, matching the "Nx zoom" convention used throughout every
weapon .ltx). With the old formula, an ironsight zoom_factor of 1.8
produced an actual camera FOV of ~1.35 degrees (g_fov=67.5 default)
for every single weapon on RMB aim, regardless of which gun -
explaining the "magnification way too strong / camera hopping"
report across AK-74U, PM, and TOZ-66 alike (hopping was normal weapon
sway made huge by the near-zero FOV, not a separate camera bug).

Changed the formula to (g_fov / zoom_factor) * 0.75, which divides
down from the base FOV as the data assumes. Kept the existing *0.75
tail so the change is a single targeted operator fix rather than an
unrelated tuning pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix ADS FOV formula: zoom_factor is a divisor, not an absolute FOV
ui_actor_state_wnd::UpdateActorInfo() (UIActorStateInfo.cpp) bound the
"stamina_state" bar in actor_menu_16.xml to conditions.GetPower(),
i.e. the actor's stamina/power stat. But Dead Air repurposed that
bar's tooltip text (st_ui_stamina_sensor_inv is localized as
"Satiety", body text entirely about hunger) without updating the
C++ binding to match, so the bar visually behaved like stamina
(recovering just from standing still/waiting) while being labeled
and described as satiety - exactly backwards from the real, already-
correct satiety model (CActorCondition::m_fSatiety only decays over
time and only rises via ChangeSatiety(), called when eating food).

Rebound the bar to conditions.GetSatiety(). Also marked
CActorCondition::GetSatiety() const so it's callable through the
const CActorCondition& already used in this function, matching
GetPower()'s existing const qualification.

Stamina itself is unaffected and still shown correctly elsewhere
(UIMotionIcon::SetPower() drives the HUD power/sprint meter).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…kable

The previous fix (dont_stack=false on ammo_base, see prior commit)
made drag-to-combine work for ammo, but it shares its mechanism with
every other place an item enters a list - including the RMB "split
stack" action, which spawns a second same-type ammo item that then
gets auto-picked-up back into the same bag and immediately re-merged
with the original, undoing the split.

Added a one-shot suppression flag on CInventoryItem
(FSuppressAutoStackOnce / SetSuppressAutoStackOnce /
ConsumeSuppressAutoStackOnce) that CUICellContainer::FindSimilar
checks (and clears) when considering a candidate, exposed to Lua as
itm:suppress_auto_stack_once(). itms_manager.script's
inv_item_split_ammo now calls it on the original item right after
halving its count, so only that one re-insertion is exempted from
auto-merging - explicit drag-and-drop combining still works normally
afterward, and every other auto-stack-on-pickup case (food, drugs,
etc.) is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Log evidence showed the boolean suppression flag never got cleared
for the item that stays behind after a split: ClearSuppressAutoStackOnce()
only ran once the *placed* item reached SetItem(cell_pos), but the
original half's UI cell is never re-inserted after a split (its count
is just mutated in place), so it would have stayed permanently
unmergeable for the rest of the session.

Replaced the boolean flag with a 2-second time-based expiry
(m_dwSuppressAutoStackUntil vs Device.dwTimeGlobal) on
CInventoryItem. This naturally covers the whole split-then-repick-up
sequence (including AddSimilar being called more than once per
placement) without needing to track a "was it placed" event at all,
and it can't get stuck on.

Diagnostic Msg() logging left in for one more verification round -
not for merge, will be stripped once confirmed working.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fighting the generic inventory-list auto-stack path (dont_stack=false
+ CUICellContainer::AddSimilar) for ammo turned out fragile: it fires
on every list insertion (drag, pickup, split re-pickup alike), called
AddSimilar multiple times per placement, and produced inconsistent
merges. Dead Air already ships a purpose-built, dedicated ammo
consolidation system for exactly this - gamedata/scripts/
ammo_aggregation.script's actor_on_item_take - which combines same-
section fragments up to each ammo type's authored box_size and
releases the emptied entities, entirely separate from generic UI
grouping. It was just never enabled (whole body commented out).

Reverted the ammo_base dont_stack=false data fix (loose gamedata,
not tracked here) and the now-unneeded UIDragDropListEx.cpp changes
back to stock. Kept the CInventoryItem time-based suppression
mechanism (SetSuppressAutoStackOnce/IsSuppressingAutoStack, added
previously) since it's still needed - exposed a read-only
is_suppressing_auto_stack() Lua getter for it so
ammo_aggregation.script can skip a just-split item when collecting
merge candidates, the same way the UI code used to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CUIActorMenu::DropItemOnAnotherItem() - Dead Air's native hook that
detects "item A was dropped directly onto item B" and forwards to the
Lua CUIActorMenu_OnItemDropped callback (which already has fully
correct, working handlers for ammo/consumable/map-tablet combining in
itms_manager.script) - resolved the target cell via
PickCell(old_owner->GetDragItemPosition()).

GetDragItemPosition() returns the dragged ghost icon's tracked
top-left corner (cursor position plus a fixed offset captured at drag
start, from wherever within the icon the player originally grabbed
it), not the cursor position itself. Cell lookup needs to know which
cell is under the cursor right now, not under the icon's corner -
those only coincide when the player happens to grab the icon near its
own top-left corner. For any other grab point the computed cell was
frequently off by one, so _citem resolved to nullptr (or the wrong
item), the Lua drop-on-item callback silently never fired, and the
drop fell through to a plain reposition instead of combining - this
is the root cause of "combining ammo/consumables only works
sometimes" across everything tested today.

Switched to GetUICursor().GetCursorPosition() directly, matching the
same absolute coordinate space PickCell()/GetAbsolutePos() already
expect (confirmed by how CUIDragDropListEx::Update() compares the raw
cursor position against absolute window rects the same way).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splitting an ammo stack was still triggering full aggregation
consolidation of *other*, unrelated ammo stacks as a side effect - the
per-item suppression flag only protected the specific original stack
from being re-absorbed, but ammo_aggregation.script's job is to sweep
and consolidate everything of that type, so any other pre-existing
fragments still got glued together whenever the split's spawned half
was auto-picked-up and triggered a consolidation pass.

Replaced with a blanket time gate in the scripts instead (loose
gamedata, not tracked here): itms_manager.script now stamps a global
last_ammo_split_time on split, and ammo_aggregation.script's
actor_on_item_take skips its entire consolidation pass for 2 seconds
after any split, regardless of which item's pickup triggered it - so
a split only ever affects the specific stack being split.

That makes the CInventoryItem::SetSuppressAutoStackOnce/
IsSuppressingAutoStack pair (and their Lua bindings) dead code with no
remaining callers - removed rather than left unused.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…closing

F is bound to kUSE (world interact) but the engine's default keybinding
table also maps it as a secondary keyboard bind for kUI_ACCEPT. Inside
the inventory grid, CUICellItem::OnKeyboardAction treats kUI_ACCEPT on a
hovered cell as a double-click, so pressing F while hovering an item
equipped/unequipped it instead of closing the screen.

CUIActorMenu::OnKeyboardAction now intercepts kUSE first and closes the
window (same as Escape/I), before the event can reach the focused cell
item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix: F key in inventory/container windows equips/unequips instead of …
…ion list

Dead Air's authored actor_menu_item_16.xml has a Reliability row and
condition/durability rows in wpn_params and outfit_info that the ported
CUIWpnParams/CUIOutfitInfo never had members for. Also wires up the
per-part malfunction list (already fully implemented in loose Lua as
items_condition.script) into the tooltip description text.

- UIWpnParams.h/.cpp: add Reliability functor+bar and Condition
  icon/label/value, reading GetConditionToShow() and
  ui_wpn_params.GetReliability (previously unused).
- UIOutfitInfo.h/.cpp: add the same Condition display for suits/helmets.
- UIItemInfo.cpp: BuildItemDescriptionText() appends the
  st_condition_type malfunction bullet list for weapons with a nonzero
  GetWeaponConditionType().
- xrServer_Objects_ALife_Items.h/.cpp: add m_weapon_condition_type to
  CSE_ALifeItemWeapon so coc_treasure_manager.script's loot-spawn roll
  (previously silently dropped) actually reaches the live object via
  STATE_Read/Write, guarded on remaining bytes for old spawn data.
- Weapon.cpp (net_Spawn): copy the ALife seed value only when the item
  has no prior session history (client_data empty), so it doesn't
  clobber a value net_Load already restored from a save.
- inventory_item.cpp (save/load): persist m_weapon_condition_type in
  the session save format as a marker+value pair rather than a bare
  trailing field, since weapon subclasses always append more data
  after this point even in old saves — a plain "bytes remaining"
  check can't tell old format from new here. Old saves verified to
  still load correctly.

Two further blockers (loose Lua, no C++ rebuild) had to be fixed
before the malfunction-roll-on-jam path actually worked end-to-end;
see HANDOFF-DeadAir-OpenXRay.md for the full writeup:
- bind_gr_gun.script: typo (ggun_binder -> gravi_gun_binder) was
  silently aborting axr_main's on_game_start() dispatch for every
  mod script, not just its own.
- bind_stalker_ext.script: actor_on_weapon_jammed was missing a
  parameter, so the native callback's auto-prepended self arg shifted
  the real weapon argument out of the declared param list.

User-confirmed in-game: tooltip and repair screen now show/persist
malfunctions correctly across reload, and old saves still load fine.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nd-malfunctions

Fix weapon/suit tooltip missing reliability, durability, and malfunct…
Dead Air's weapon addon icon overlays (scope/etc.) are driven by
numbered "Nicon_layer" keys (1icon_layer, 1icon_layer_x, ...) read in
CUIInventoryCellItem's constructor. The loop started at index 0 and
bailed out via `break` as soon as a numbered key didn't exist, but no
config in gamedata ever defines "0icon_layer" - every weapon variant
starts numbering at 1. So the loop always broke on the very first
check and the layer icon was never created for any item.

This made scope attachment look broken: the weapon itself (3D model,
zoom, HUD) is swapped via a separate Lua-driven mechanism
(dxr_scopes.script cloning the weapon into a new section) and worked
fine, but the small scope icon overlay on the inventory icon never
appeared. Silencer/launcher addons were unaffected since they use an
older, separate native engine mechanism (CWeaponMagazined addon
flags + CUIWeaponCellItem eSilencer/eLauncher icons) that doesn't
go through this loop at all.

Fix: start the loop at i = 1 to match the data convention.
Fix: scope icon overlay never rendered on weapon inventory icons
The condition row's caption passed the raw localization key
("ui_inv_af_condition") instead of translating it, unlike every sibling
row in the same function.

The restore/immunity/weight effects were always read fresh from the
static ltx template via pSettings, ignoring Dead Air's runtime artefact
tuning (CArtefact::Set*Power/SetAdditionalWeight/SetArtefactImmunity,
used for IAM quality-tier mutations). Artefacts whose real effect
magnitudes were set dynamically at spawn showed stale/zero data in the
tooltip. SetInfo() now prefers the live CArtefact instance's values
when the item is one, falling back to static config otherwise.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nd-effects

Fix artefact tooltip: untranslated condition caption and stale effects
Regular (non-trader) stalkers in Dead Air are flagged <barter_mode>1</barter_mode>
in their character profile and are supposed to exchange goods for goods only,
never for money: the trade screen shows a single exchange button and the deal
goes through as soon as what the player offers is worth at least as much as what
he is taking. Stock OpenXRay has no notion of barter at all, so every NPC opened
the ordinary money trade screen with separate Buy/Sell buttons.

- specific_character: parse and expose <barter_mode>, mirroring <mechanic_mode>.
- CUIActorMenu: create the trade_barter_button that Dead Air's actor_menu XML
  already defines (optional, so layouts without it still load); in trade mode
  show either the barter button or the buy/sell pair depending on the partner's
  flag.
- OnBtnPerformBarter: compares the same two totals the trade bars already
  display and, when the offer covers the ask, transfers both directions with
  CTrade::TransferItem(..., bFree=true) so no money changes hands. Otherwise it
  shows the existing trade_dont_make message.
- TransferItems gained a defaulted bFree parameter; the money trade paths are
  unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dead Air: restore goods-for-goods barter with ordinary NPCs
…ect ratio

UICore::get_xml_name() picked the plain (non-widescreen) XML file whenever
is_widescreen() was false, and only tried "<name>_16.xml" otherwise. Dead
Air / DeadZone only maintains the "_16" layouts: the plain XMLs still in the
archives are stale leftovers from the mod's base (different skin, missing
nodes, and in several cases entire features the mod replaced - e.g.
ui_mm_faction_select.xml is still the old CoC faction picker, actor_menu.xml
has no backpack/sidearm/binocular slots, ui_mm_main.xml has no
<background_words> so it hard-errors in CUIXmlInitBase::InitWindow). Picking
by aspect ratio meant any 4:3/5:4 resolution silently swapped in a broken UI.

Also fixes a related bug in the same function: when building the "_16" name
for an extension-less caller, the stock code appended "_16" to the bare name
without ever adding ".xml" first, so the follow-up FS.exist() probe could
never find the file for those callers.

Now always prefers "<name>_16.xml" if it exists, regardless of aspect ratio,
and falls back to the plain file only when no "_16" variant exists -
identical behavior to stock for every file that has no widescreen variant.
Fix UI layout selection: prefer the maintained "_16" XML at every asp…
12 checkboxes/sliders in ui_mm_opt_16.xml (r__actor_body, r2_sss_intensity/
enable, r2_lumasharpen, r2_fxaa, r2_technicolor, r2_vignette, r2_lenswater,
r2_lensdirt, r2_reflections, hud_draw_info, hud_draw_map) referenced console
variables stock OpenXRay never registered, so Apply silently failed and the
UI always reverted to off. Registered all of them (storage-only, matching
the existing missing-render-cvars fix pattern) so settings persist.

r__actor_body additionally gets real behavior: the actor is normally
excluded from its own color-pass and shadow-map rendering entirely (never
needed before, since the local player never saw their own body). When
enabled:
- color pass: renders the actor's base body visual (legs-only when an
  outfit's actor_visual is worn, by design — the separate first-person HUD
  hands/arms are used instead of a body head/hands)
- shadow map: additionally renders a full-detail stand-in visual (the same
  model regular NPCs use) with its bone transforms retargeted from the
  actor's live pose, so the cast shadow has a complete head+arms silhouette
  that matches the actor's real animation instead of the legs-only geometry
  or a static pose
- attachments (torch/headlamp, radio) render for the shadow but not the
  color pass, since the legs-only model has no head to visually mount the
  headlamp on

InventoryOwner.cpp also stops skipping CAttachmentOwner rendering for the
locally-controlled actor (previously dead code, since the actor was never
rendered at all) while still avoiding a double-drawn weapon (already
handled separately by the HUD system).

Known remaining issue: camera clips through the torso while climbing
ladders. Not fixed — see HANDOFF-DeadAir-OpenXRay.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix options-menu cvars that never saved; add player-body visibility
The §44 first-person body render force-draws the actor's own visual
every frame, but had no way to know when the camera pose made that
body clip the view (a camera-to-bone distance heuristic was tried and
proved unworkable, since that distance barely changes between normal
standing and climbing).

Add a minimal cross-DLL query instead: IGameObject::climbing()
(default false in CGameObject, overridden in CActor to read the
existing mcClimb movement-state flag). The render DLL's PHASE_NORMAL
body force-injection now skips the draw outright while climbing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mikhailRo and others added 10 commits July 27, 2026 23:49
Fix actor body clipping the camera while climbing a ladder
itms_manager.script's actor_on_item_take_from_ground handler already plays
the inv_take sound and shows a lower-left PDA news popup with the item's
name, but was dead: GameObject::eTakeItemFromGround was registered for
script binding but never invoked from any C++ call site. Fire it from both
real ground-pickup call sites in Actor_Feel.cpp (PickupModeUpdate and
PickupModeUpdate_COD), right after the existing SendPickUpEvent call.

Deliberately not hooked into the shared GE_OWNERSHIP_TAKE network-event
handler in Actor_Events.cpp: that same event also fires when existing
inventory items re-materialize on level load/save-restore, which would
have spammed the notification for the player's whole inventory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion

Fire native ground-pickup event so Dead Air's item-take news/sound fires
… shadow

Follow-up to feat/actor-body-visibility-options (§44) and
fix/ladder-climb-body-clip (§45). Two independent bugs, ten passes to
fully root-cause (see HANDOFF-DeadAir-OpenXRay.md §47 for the full
investigation, including three dead ends kept for the record):

1. Body/shadow popped into view facing the wrong way when turning the
   camera fast while standing still. Root cause: CActor::g_cl_Orientate's
   pre-existing mcTurn animation-catchup lerp (model orientation chases
   camera yaw over ~1s), invisible before the actor's own body was ever
   rendered. Added IGameObject::turning_in_place() cross-DLL query
   (same pattern as climbing()) and skip the body/shadow draw while it's
   active.

2. Shadow showed a duplicate/doubled silhouette, then legs-only, then a
   fixed-size blob across successive fix attempts — three distinct real
   bugs stacked on top of each other:
   - A data race: 3 parallel sun-cascade threads sharing one mutable
     shadow-model instance. Fixed with a per-context_id instance array.
   - That fix exposed a second race in CModelPool::Create (now callable
     concurrently). Fixed with a Lock around just the creation call.
   - CHUDManager::Render_First (the original, pre-§44 "weapon shadow"
     code) has always also drawn the actor's own legs-only base visual
     unconditionally, redundant with the new full-detail shadow stand-in.
     Added IRender::actor_body_shadow_active() cross-DLL query to skip
     it when the replacement is active.
   - add_Visual's internal CalculateBones(TRUE) call was silently
     discarding the retargeted pose one line after it was set (an
     accidental early-out from the old shared-instance code had been
     masking this). Fixed by calling CalculateBones ourselves first, so
     our retargeted pose becomes the last write.

Engine-built (0 errors) after every change; user-confirmed in-game for
both symptoms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix actor-body render/shadow quirks: camera-turn pop-in, doubled/blob…
- ls_header/ls_tip_number/ls_tip_N text was rendering as a raw
  untranslated placeholder key and never changed between loads
  (gamedata loadscreen.script had get_tip_number() hardcoded to
  return 2, and ls_tip_number was missing from the string table --
  both fixed in loose gamedata, not here).
- Repositioned loading_header/loading_tip_number/loading_tip so the
  text no longer overlapped the progress bar.
- loading_progress lacked under_background="0" (unlike the ClearSky/
  SoC variants), so it defaulted to drawing UNDER the full-screen
  background photo layer, which alpha-blended over it -- this is why
  the bar looked hazy/desaturated and why it got more noticeable
  later in loading (the growing white fill blended more visibly than
  the static black background). Fixed by drawing it on top.
- Measured the background texture's baked-in decorative "groove"
  bar pixel-by-pixel (ui_actor_loadgame_screen.dds) and repositioned/
  resized loading_progress to sit exactly inside it instead of
  floating above it.
- Brightened the tip text color (103,103,103 -> 200,200,200) for
  legibility against the busy background art.

Applies to both the 4:3 (LoadingScreenXML) and 16:9
(LoadingScreenXML16x9) Call of Pripyat-style hardcoded loading
screen variants in UILoadingScreenHardcoded.h.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…gressbar

Fix loading-screen tip text and progress bar for Dead Air's art
…eline

r__color_base_r/g/b and r2_vibrance_val were registered as storage-only
cvars (to silence console spam) but never consumed anywhere, so the
options-menu R/G/B/Saturation sliders had zero visual effect regardless
of value.

- CRender::SetPostProcessParams (r2.cpp) now folds the color-base/add
  cvars in as an offset on top of CCameraManager's per-frame
  postprocess baseline, the same way multiple .ppe effectors already
  blend against that baseline.
- r4_rendertarget_phase_combine.cpp now sends the real r2_vibrance_val
  to the combine shader's vibrance constant instead of a hardcoded
  zero (aberration/lumasharpen stay pinned to zero -- nothing drives
  those).
- Narrowed the four sliders' registered cvar range from the spam-fix's
  -10000..10000 placeholder to 0..1 / -1..1, matching SPPInfo::SColor's
  packing and Dead Air's own script-set values.

User-confirmed in-game: R/G/B/Saturation sliders now visibly affect
the rendered image.
Wire options-menu color correction and saturation into the render pip…
…munities)

An earlier patch added set_artefact_weight/set_artefact_additional_weight and
9 per-hit-type set_artefact_*_immunity setters for Dead Air runtime artefact
tuning, but never the matching getters. itms_manager.script:container_add()
(dropping an artefact into a container item) calls the getters, which did not
exist, causing a Lua attempt to call method (a nil value) error and
occasional crash.

Adds the 11 corresponding get_artefact_* bindings, mirroring the setters:
weight reuses the existing generic Weight() getter, additional_weight reads
CArtefact::AdditionalInventoryWeight(), and the 9 immunities read
CHitImmunity::GetHitImmunity() via CArtefact::m_ArtefactHitImmunities.
@mikhailRo mikhailRo closed this Jul 30, 2026
@github-project-automation github-project-automation Bot moved this to Done in Roadmap Jul 30, 2026
@mikhailRo
mikhailRo deleted the fix/artefact-container-getters branch July 30, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants