diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 112c486..dc223f6 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -510,7 +510,11 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe state; tools remain inventory items until active hand, worn, backpack, armor, weapon, durability, animation, or mesh-attachment rules require replicated and persisted slot state. -- [ ] Add weight or carry capacity placeholder. +- [x] Add weight or carry capacity placeholder. Locked MVP carry capacity to + stack `UnitWeight`, inventory `GetTotalWeight`, character comfort/heavy carry + thresholds, strength-scaled movement penalties, and a debug HUD carried + weight readout. Later volume, backpack, awkward-object, and hard overload + rules should extend this hook. - [ ] Add inventory UI. - [x] Add replication for inventory changes. - [ ] Add persistence for inventory. diff --git a/Docs/InventoryDataModel.md b/Docs/InventoryDataModel.md index 5d775a6..e8f90ad 100644 --- a/Docs/InventoryDataModel.md +++ b/Docs/InventoryDataModel.md @@ -120,6 +120,27 @@ The 0.1.E inventory work should implement these operations on top of the model: systems layered on top. - UI: read the replicated stack list and send requests back through server RPCs. +## Carry Capacity Placeholder + +The 0.1.E MVP carry-capacity placeholder is implemented as a weight-first +movement penalty, not a hard inventory lock. Each `FAgrarianItemStack` stores +`UnitWeight`; `UAgrarianInventoryComponent::GetTotalWeight` sums +`Quantity * UnitWeight`; and `AAgrarianGameCharacter` reads that total through +`GetCurrentCarryWeight`. + +The default comfort and heavy thresholds are `25.0` and `60.0` item-weight +units. `StrengthMultiplier` scales those thresholds so stronger characters can +carry more before penalties. Movement remains full speed at or below the +effective comfort threshold, trends down toward `65%` between comfort and heavy +loads, and uses a `45%` carry multiplier at or above the heavy threshold. The +debug HUD shows current carried weight so designers can tune item weights during +play tests. + +This intentionally leaves volume, containers, backpacks, injuries, fatigue, +awkward-object handling, and hard over-encumbrance rules for later systems. +Those systems should build on the existing total-weight hook instead of adding a +parallel inventory burden model. + ## Equipment Slot Decision Dedicated equipment slots are deferred for the 0.1.E MVP. Current MVP tools, diff --git a/Docs/TechnicalDesignDocument.md b/Docs/TechnicalDesignDocument.md index 63027ce..66fe152 100644 --- a/Docs/TechnicalDesignDocument.md +++ b/Docs/TechnicalDesignDocument.md @@ -130,6 +130,14 @@ or mesh-attachment state. When that need appears, equipment should be added as server-authoritative, replicated, persisted slot state rather than as local UI selection only. +Carry capacity is active as an MVP placeholder through stack `UnitWeight`, +inventory `GetTotalWeight`, and character movement penalties. The current +character uses `25.0` comfort and `60.0` heavy item-weight thresholds, scales +those thresholds by strength, and exposes current carried weight in the debug +HUD. Future backpacks, containers, awkward-object rules, and hard overload +limits should extend this total-weight path rather than creating a second carry +model. + ## Time And Environment The MVP gameplay calendar target is: diff --git a/Scripts/verify_carry_capacity_placeholder.py b/Scripts/verify_carry_capacity_placeholder.py new file mode 100644 index 0000000..9559de9 --- /dev/null +++ b/Scripts/verify_carry_capacity_placeholder.py @@ -0,0 +1,88 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +FILES = { + "AgrarianTypes.h": ROOT / "Source" / "AgrarianGame" / "AgrarianTypes.h", + "AgrarianInventoryComponent.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianInventoryComponent.cpp", + "AgrarianGameCharacter.h": ROOT / "Source" / "AgrarianGame" / "AgrarianGameCharacter.h", + "AgrarianGameCharacter.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianGameCharacter.cpp", + "AgrarianDebugHUD.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.cpp", + "InventoryDataModel.md": ROOT / "Docs" / "InventoryDataModel.md", + "TechnicalDesignDocument.md": ROOT / "Docs" / "TechnicalDesignDocument.md", + "AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", +} + +EXPECTED = { + "AgrarianTypes.h": [ + "UnitWeight", + ], + "AgrarianInventoryComponent.cpp": [ + "UAgrarianInventoryComponent::GetTotalWeight", + "Stack.UnitWeight", + "Stack.Quantity", + ], + "AgrarianGameCharacter.h": [ + "ComfortableCarryWeight = 25.0f", + "HeavyCarryWeight = 60.0f", + "CalculateCarryWeightMovementMultiplier", + "GetCurrentCarryWeight", + ], + "AgrarianGameCharacter.cpp": [ + "AAgrarianGameCharacter::GetCurrentCarryWeight", + "InventoryComponent->GetTotalWeight()", + "CalculateCarryWeightMovementMultiplier()", + "AAgrarianGameCharacter::CalculateCarryWeightMovementMultiplier", + "StrengthMultiplier", + "FVector2D(1.0f, 0.65f)", + "return 0.45f", + ], + "AgrarianDebugHUD.cpp": [ + "GetCurrentCarryWeight()", + ], + "InventoryDataModel.md": [ + "## Carry Capacity Placeholder", + "weight-first", + "movement penalty", + "`UnitWeight`", + "`GetTotalWeight`", + "`GetCurrentCarryWeight`", + "`25.0`", + "`60.0`", + "`StrengthMultiplier`", + "`45%` carry multiplier", + "parallel inventory burden model", + ], + "TechnicalDesignDocument.md": [ + "Carry capacity is active as an MVP placeholder", + "stack `UnitWeight`", + "inventory `GetTotalWeight`", + "`25.0` comfort and `60.0` heavy", + "debug", + "HUD", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "[x] Add weight or carry capacity placeholder.", + "stack `UnitWeight`", + "inventory `GetTotalWeight`", + "strength-scaled movement penalties", + ], +} + + +def main(): + missing = [] + for label, path in FILES.items(): + text = path.read_text(encoding="utf-8") + for snippet in EXPECTED[label]: + if snippet not in text: + missing.append(f"{label}: {snippet}") + + if missing: + raise RuntimeError("Carry capacity placeholder verification failed: " + "; ".join(missing)) + + print("Agrarian carry capacity placeholder verification complete.") + + +if __name__ == "__main__": + main()