-
Notifications
You must be signed in to change notification settings - Fork 246
tweak(Controlbar): Allow replay observer to view contained units if not following player #3122
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
base: main
Are you sure you want to change the base?
Changes from all commits
d63b811
fd01ff8
0d4cf8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -884,6 +884,7 @@ ControlBar::ControlBar() | |
| m_commandSets = nullptr; | ||
| m_controlBarSchemeManager = nullptr; | ||
| m_isObserverCommandBar = FALSE; | ||
| m_isReadOnly = FALSE; | ||
| m_observerLookAtPlayer = nullptr; | ||
| m_observedPlayer = nullptr; | ||
| m_buildToolTipLayout = nullptr; | ||
|
|
@@ -1321,6 +1322,7 @@ void ControlBar::reset() | |
| m_displayedOCLTimerSeconds = 0; | ||
|
|
||
| m_isObserverCommandBar = FALSE; // reset us to use a normal command bar | ||
| m_isReadOnly = FALSE; | ||
| m_observerLookAtPlayer = nullptr; | ||
| m_observedPlayer = nullptr; | ||
|
|
||
|
|
@@ -1479,6 +1481,26 @@ void ControlBar::update() | |
| exitPosition = obj->getObjectExitInterface()->getRallyPoint(); | ||
|
|
||
| showRallyPoint(exitPosition); | ||
|
|
||
| ContainModuleInterface* observerContain = obj ? obj->getContain() : nullptr; | ||
| Bool showObserverInventory = (observerContain != nullptr && observerContain->getContainMax() > 0); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is including non-garrisonable containers intentional? If yes, the fixed 10-slot layout needs bounding (there's a bot comment on populateButtonProc). If not, matching the isGarrisonable() gate resolves both. |
||
|
|
||
| if (showObserverInventory && m_observerLookAtPlayer == nullptr) | ||
|
Comment on lines
+1485
to
+1488
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. Inventory slots overflow ControlBar::update() now switches observers into CB_CONTEXT_STRUCTURE_INVENTORY for any selected object with getContainMax() > 0, but the structure inventory UI only supports 10 occupant slots. If a container ever has >10 contained objects (e.g., tunnel networks when MaxTunnelCapacity is configured above 10), populateStructureInventory() will call populateButtonProc() past the supported slot count, tripping the MAX_STRUCTURE_INVENTORY_BUTTONS assert and/or overwriting non-inventory buttons. Agent Prompt
|
||
| { | ||
| if (!isApparentControllingPlayerNeutral(obj)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This return sits above the else if that restores CB_CONTEXT_OBSERVER_LIST, so a failed neutrality check leaves the previous container's inventory on screen. It's reachable for a defeated player who becomes an observer, though I don't think for a replay observer if that helps. Maybe |
||
| return; | ||
| } | ||
|
Comment on lines
+1488
to
+1492
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. Observer inventory early return In observer-mode ControlBar::update(), selecting a container that fails isApparentControllingPlayerNeutral(obj) returns immediately, bypassing the fallback that switches the UI back to CB_CONTEXT_OBSERVER_LIST. This can leave stale structure-inventory UI visible after selecting a disallowed container. Agent Prompt
|
||
|
|
||
| if (m_currContext != CB_CONTEXT_STRUCTURE_INVENTORY || m_currentSelectedDrawable != drawToEvaluateFor) | ||
| switchToContext(CB_CONTEXT_STRUCTURE_INVENTORY, drawToEvaluateFor); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could the observer inventory be made read-only at the UI boundary? populateStructureInventory() enables the occupant, Evacuate, and Stop buttons, and assigning a real m_currentSelectedDrawable lets clicks reach processCommandUI() and emit MSG_EXIT, MSG_EVACUATE, or MSG_DO_STOP.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for the review. After the new push, none of the buttons are enabled or can be pressed from the observer's POV. |
||
| else | ||
| updateContextStructureInventory(); | ||
| } | ||
| else if (m_currContext != CB_CONTEXT_OBSERVER_LIST) | ||
| { | ||
| switchToContext(CB_CONTEXT_OBSERVER_LIST, nullptr); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
@@ -1805,24 +1827,12 @@ void ControlBar::evaluateContextUI() | |
| ContainModuleInterface *contain = obj->getContain(); | ||
| if( contain && contain->getContainMax() > 0 ) | ||
| { | ||
|
|
||
| const Player *otherPlayer = contain->getApparentControllingPlayer(ThePlayerList->getLocalPlayer()); | ||
| if (!otherPlayer) | ||
| otherPlayer = obj->getControllingPlayer(); | ||
| Player *player = ThePlayerList->getLocalPlayer(); | ||
|
|
||
| if( !player || !otherPlayer ) | ||
| { | ||
| //Sanity. | ||
| return; | ||
| } | ||
| Relationship relation = player->getRelationship( otherPlayer->getDefaultTeam() ); | ||
|
|
||
| Bool apparentControllingPlayerNeutral = isApparentControllingPlayerNeutral(obj); | ||
| //Note: All following checks already account for the fact that this object | ||
| //isn't ours. | ||
|
|
||
| //The only case we can actually see a non-controlled controlbar is a neutral garrisonable structure. | ||
| if( !contain->isGarrisonable() || relation != NEUTRAL ) | ||
| if( !contain->isGarrisonable() || !apparentControllingPlayerNeutral) | ||
| { | ||
| //Can't peek inside enemy/allied containers period! | ||
| return; | ||
|
|
@@ -2789,6 +2799,7 @@ void ControlBar::setControlBarSchemeByPlayer(Player *p) | |
| if( !p->isPlayerActive() ) | ||
| { | ||
| m_isObserverCommandBar = TRUE; | ||
| m_isReadOnly = TRUE; | ||
|
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
|
||
| switchToContext( CB_CONTEXT_OBSERVER_LIST, nullptr ); | ||
| DEBUG_LOG(("We're loading the Observer Command Bar")); | ||
|
|
||
|
|
@@ -2803,6 +2814,7 @@ void ControlBar::setControlBarSchemeByPlayer(Player *p) | |
| { | ||
| switchToContext( CB_CONTEXT_NONE, nullptr ); | ||
| m_isObserverCommandBar = FALSE; | ||
| m_isReadOnly = FALSE; | ||
|
|
||
| if (buttonPlaceBeacon) | ||
| buttonPlaceBeacon->winHide( | ||
|
|
@@ -2834,6 +2846,7 @@ void ControlBar::setControlBarSchemeByPlayerTemplate( const PlayerTemplate *pt) | |
| if(pt == ThePlayerTemplateStore->findPlayerTemplate(TheNameKeyGenerator->nameToKey("FactionObserver"))) | ||
| { | ||
| m_isObserverCommandBar = TRUE; | ||
| m_isReadOnly = TRUE; | ||
| switchToContext( CB_CONTEXT_OBSERVER_LIST, nullptr ); | ||
| DEBUG_LOG(("We're loading the Observer Command Bar")); | ||
|
|
||
|
|
@@ -2848,6 +2861,7 @@ void ControlBar::setControlBarSchemeByPlayerTemplate( const PlayerTemplate *pt) | |
| { | ||
| switchToContext( CB_CONTEXT_NONE, nullptr ); | ||
| m_isObserverCommandBar = FALSE; | ||
| m_isReadOnly = FALSE; | ||
|
|
||
| if (buttonPlaceBeacon) | ||
| buttonPlaceBeacon->winHide( | ||
|
|
@@ -3582,6 +3596,25 @@ Bool ControlBar::canShowSpecialPowerShortcut() const | |
| return false; | ||
| } | ||
|
|
||
| //------------------------------------------------------------------------------------------------- | ||
| Bool ControlBar::isApparentControllingPlayerNeutral(const Object* obj) const | ||
| { | ||
| ContainModuleInterface* contain = obj->getContain(); | ||
| const Player* otherPlayer = contain->getApparentControllingPlayer(ThePlayerList->getLocalPlayer()); | ||
| if (!otherPlayer) | ||
| otherPlayer = obj->getControllingPlayer(); | ||
| const Player* player = ThePlayerList->getLocalPlayer(); | ||
|
|
||
| if (!player || !otherPlayer) | ||
| { | ||
| //Sanity. | ||
| return FALSE; | ||
| } | ||
|
|
||
| Relationship relation = player->getRelationship(otherPlayer->getDefaultTeam()); | ||
| return relation == NEUTRAL; | ||
| } | ||
|
|
||
| //------------------------------------------------------------------------------------------------- | ||
| void ControlBar::updateSpecialPowerShortcut() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,7 +83,7 @@ void ControlBar::populateButtonProc( Object *obj, void *userData ) | |
| GadgetButtonDrawOverlayImage( info->inventoryButtons[ info->buttonIndex ], image ); | ||
|
|
||
| // Enable the button | ||
| info->inventoryButtons[ info->buttonIndex ]->winEnable( TRUE ); | ||
| info->inventoryButtons[ info->buttonIndex ]->winEnable( !info->self->m_isReadOnly ); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The DEBUG_ASSERTCRASH at line 68 is compiled out in release, so buttonIndex keeps incrementing past MAX_STRUCTURE_INVENTORY_BUTTONS (10). |
||
|
|
||
| // move to the next button index | ||
| info->buttonIndex++; | ||
|
|
@@ -170,7 +170,7 @@ void ControlBar::populateStructureInventory( Object *building ) | |
| m_commandWindows[ STOP_ID ]->winHide( FALSE ); | ||
|
|
||
| // if there is at least one item in there enable the evacuate and stop buttons | ||
| if( contain->getContainCount() != 0 ) | ||
| if(!m_isReadOnly && contain->getContainCount() != 0 ) | ||
| { | ||
| m_commandWindows[ EVACUATE_ID ]->winEnable( TRUE ); | ||
| m_commandWindows[ STOP_ID ]->winEnable( TRUE ); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m_isReadOnly tracks m_isObserverCommandBar - both are set at the same six sites, always to the same value. Could we have the two inventory call sites use m_isObserverCommandBar directly (or isObserverControlBarOn()) and drop this member?