Skip to content

Commit 36e4584

Browse files
committed
Refactoring
1 parent 1b71b1b commit 36e4584

File tree

8 files changed

+162
-212
lines changed

8 files changed

+162
-212
lines changed

Source/controls/local_coop/local_coop.cpp

Lines changed: 74 additions & 133 deletions
Large diffs are not rendered by default.

Source/controls/local_coop/local_coop.hpp

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,6 @@ struct LocalCoopState {
122122
/// Player 1 (index 0) is always marked as active when local coop is enabled
123123
std::array<LocalCoopPlayer, MaxLocalPlayers> players;
124124

125-
/// D-pad repeat delay in milliseconds
126-
static constexpr uint32_t DpadRepeatDelay = 300;
127-
128125
/// Panel ownership: which game player ID controls the currently open panels
129126
/// 0 = player 1 (default), 1-3 = local coop players 2-4
130127
/// Use -1 to indicate no explicit owner (falls back to player 1)
@@ -159,14 +156,6 @@ struct LocalCoopState {
159156
int64_t cameraSmoothScreenX = 0;
160157
int64_t cameraSmoothScreenY = 0;
161158

162-
/// Dead zone radius in screen pixels - camera won't move if average player position
163-
/// is within this distance from the current camera target
164-
static constexpr int CameraDeadZone = 32;
165-
166-
/// Camera smoothing factor (0.0 = no smoothing, 1.0 = instant)
167-
/// Higher values = faster camera response but potentially jerky movement
168-
static constexpr float CameraSmoothFactor = 0.25f;
169-
170159
/// Check if a local coop player owns the panels (not player 1)
171160
[[nodiscard]] bool HasPanelOwner() const { return panelOwnerPlayerId > 0; }
172161

@@ -209,11 +198,6 @@ struct LocalCoopState {
209198
[[nodiscard]] LocalCoopPlayer *GetPlayer(uint8_t playerId);
210199
[[nodiscard]] const LocalCoopPlayer *GetPlayer(uint8_t playerId) const;
211200

212-
/// Get the LocalCoopPlayer for a coop player (players 2-4) - deprecated, use GetPlayer instead
213-
/// @param playerId Game player ID (1-3 for coop players)
214-
/// @return Pointer to LocalCoopPlayer, or nullptr if invalid or player 1
215-
[[nodiscard]] LocalCoopPlayer *GetCoopPlayer(uint8_t playerId);
216-
[[nodiscard]] const LocalCoopPlayer *GetCoopPlayer(uint8_t playerId) const;
217201
};
218202

219203
extern LocalCoopState g_LocalCoop;
@@ -531,9 +515,9 @@ void AssignLocalCoopSpellToSlot(uint8_t playerId, int slotIndex);
531515
* @brief Load available heroes for local co-op player selection.
532516
*
533517
* Excludes heroes already selected by other local players.
534-
* @param playerId Game player ID (0 = player 1, 1-3 = coop players)
518+
* @param playerIdx Game player index (same as Players[] / g_LocalCoop.players[]: 0–3).
535519
*/
536-
void LoadAvailableHeroesForLocalPlayer(uint8_t playerId);
520+
void LoadAvailableHeroesForCoopSlot(uint8_t playerIdx);
537521

538522
/**
539523
* @brief Confirm character selection and spawn a local co-op player.
@@ -863,10 +847,9 @@ uint8_t GetLocalCoopStoreOwnerPlayerId();
863847
/**
864848
* @brief Close the active store and clear local co-op store ownership.
865849
*
866-
* This is a convenience function that combines setting ActiveStore to None
867-
* and clearing local co-op store ownership. Use this instead of manually
868-
* setting ActiveStore = TalkID::None followed by ClearLocalCoopStoreOwner().
850+
* Sets ActiveStore to None and clears local co-op store ownership (e.g. stick input
851+
* for the prior store owner). Prefer this over assigning ActiveStore directly.
869852
*/
870-
void CloseStore();
853+
void CloseLocalCoopStore();
871854

872855
} // namespace devilution

Source/controls/local_coop/local_coop_button_mapper.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Implementation of button mapping utilities for local co-op.
55
*/
66
#include "controls/local_coop/local_coop_button_mapper.hpp"
7+
#include "controls/local_coop/local_coop_constants.hpp"
78

89
#ifndef USE_SDL1
910
#ifdef USE_SDL3
@@ -19,13 +20,13 @@ int LocalCoopButtonMapper::GetSkillSlot(ControllerButton button)
1920
{
2021
switch (button) {
2122
case ControllerButton_BUTTON_A:
22-
return ButtonToSkillSlot[0]; // A -> slot 2
23+
return LocalCoopInput::ButtonToSkillSlot[0]; // A -> slot 2
2324
case ControllerButton_BUTTON_B:
24-
return ButtonToSkillSlot[1]; // B -> slot 3
25+
return LocalCoopInput::ButtonToSkillSlot[1]; // B -> slot 3
2526
case ControllerButton_BUTTON_X:
26-
return ButtonToSkillSlot[2]; // X -> slot 0
27+
return LocalCoopInput::ButtonToSkillSlot[2]; // X -> slot 0
2728
case ControllerButton_BUTTON_Y:
28-
return ButtonToSkillSlot[3]; // Y -> slot 1
29+
return LocalCoopInput::ButtonToSkillSlot[3]; // Y -> slot 1
2930
default:
3031
return -1;
3132
}
@@ -37,27 +38,27 @@ int LocalCoopButtonMapper::GetSkillSlot(uint8_t sdlButton)
3738
#ifdef USE_SDL3
3839
switch (sdlButton) {
3940
case SDL_GAMEPAD_BUTTON_SOUTH:
40-
return ButtonToSkillSlot[0]; // A (South) -> slot 2
41+
return LocalCoopInput::ButtonToSkillSlot[0]; // A (South) -> slot 2
4142
case SDL_GAMEPAD_BUTTON_EAST:
42-
return ButtonToSkillSlot[1]; // B (East) -> slot 3
43+
return LocalCoopInput::ButtonToSkillSlot[1]; // B (East) -> slot 3
4344
case SDL_GAMEPAD_BUTTON_WEST:
44-
return ButtonToSkillSlot[2]; // X (West) -> slot 0
45+
return LocalCoopInput::ButtonToSkillSlot[2]; // X (West) -> slot 0
4546
case SDL_GAMEPAD_BUTTON_NORTH:
46-
return ButtonToSkillSlot[3]; // Y (North) -> slot 1
47+
return LocalCoopInput::ButtonToSkillSlot[3]; // Y (North) -> slot 1
4748
default:
4849
return -1;
4950
}
5051
#else
5152
// SDL2 uses SDL_GameControllerButton enum
5253
switch (sdlButton) {
5354
case SDL_CONTROLLER_BUTTON_A:
54-
return ButtonToSkillSlot[0]; // A -> slot 2
55+
return LocalCoopInput::ButtonToSkillSlot[0]; // A -> slot 2
5556
case SDL_CONTROLLER_BUTTON_B:
56-
return ButtonToSkillSlot[1]; // B -> slot 3
57+
return LocalCoopInput::ButtonToSkillSlot[1]; // B -> slot 3
5758
case SDL_CONTROLLER_BUTTON_X:
58-
return ButtonToSkillSlot[2]; // X -> slot 0
59+
return LocalCoopInput::ButtonToSkillSlot[2]; // X -> slot 0
5960
case SDL_CONTROLLER_BUTTON_Y:
60-
return ButtonToSkillSlot[3]; // Y -> slot 1
61+
return LocalCoopInput::ButtonToSkillSlot[3]; // Y -> slot 1
6162
default:
6263
return -1;
6364
}
@@ -76,7 +77,7 @@ int LocalCoopButtonMapper::GetBeltSlot(int buttonIndex, bool leftShoulderHeld, b
7677
return -1;
7778

7879
const int baseSlot = leftShoulderHeld ? 0 : 4;
79-
return baseSlot + ButtonToBeltOffset[buttonIndex];
80+
return baseSlot + LocalCoopInput::ButtonToBeltOffset[static_cast<size_t>(buttonIndex)];
8081
}
8182

8283
int LocalCoopButtonMapper::GetButtonIndex(uint8_t sdlButton)

Source/controls/local_coop/local_coop_button_mapper.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,6 @@ class LocalCoopButtonMapper {
8080
static std::string_view GetBeltButtonLabel(int buttonIndex);
8181

8282
private:
83-
// Button to skill slot mapping: A=2, B=3, X=0, Y=1
84-
static constexpr int ButtonToSkillSlot[4] = { 2, 3, 0, 1 };
85-
86-
// Button to belt offset mapping: A=0, B=1, X=2, Y=3
87-
static constexpr int ButtonToBeltOffset[4] = { 0, 1, 2, 3 };
88-
8983
// Skill slot button labels: slot 0=X, slot 1=Y, slot 2=A, slot 3=B
9084
static constexpr std::string_view SkillSlotLabels[4] = { "X", "Y", "A", "B" };
9185

Source/controls/local_coop/local_coop_constants.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ constexpr int BaseContentWidth = MinBeltWidth - 7;
100100
constexpr int BaseWidth = LeftBorderPadding + BaseContentWidth + RightBorderPadding;
101101
} // namespace PanelWidth
102102

103+
/// Shared-screen bounds for local co-op (IsTilePositionOnScreen)
104+
namespace SharedScreen {
105+
constexpr int TileToScreenXMultiplier = 32;
106+
constexpr int TileToScreenYMultiplier = 16;
107+
constexpr int MaxDistanceFromRightEdge = 100;
108+
constexpr int MaxDistanceFromViewportHalfHeight = 80;
109+
constexpr int NormalizationScale = 1000;
110+
constexpr int64_t EllipseOutsideThresholdSq = 1000000;
111+
constexpr uint8_t ExcludeNoPlayer = 255;
112+
} // namespace SharedScreen
113+
103114
} // namespace LocalCoopLayout
104115

105116
namespace LocalCoopInput {

Source/pfile.cpp

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pfile.h"
77

88
#include <cstdint>
9+
#include <functional>
910
#include <string>
1011
#include <string_view>
1112

@@ -668,43 +669,60 @@ void sfile_write_stash()
668669
Stash.dirty = false;
669670
}
670671

671-
bool pfile_ui_set_hero_infos(bool (*uiAddHeroInfo)(_uiheroinfo *))
672+
namespace {
673+
674+
template <typename Fn>
675+
bool pfile_ui_set_hero_infos_impl(Fn &&fn)
672676
{
673677
memset(hero_names, 0, sizeof(hero_names));
674678

675679
uint32_t originalSaveNumber = gSaveNumber;
676680
for (uint32_t i = 0; i < MAX_CHARACTERS; i++) {
677681
std::optional<SaveReader> archive = OpenSaveArchive(i);
678-
if (archive) {
679-
PlayerPack pkplr;
680-
if (ReadHero(*archive, &pkplr)) {
681-
_uiheroinfo uihero;
682-
uihero.saveNumber = i;
683-
strcpy(hero_names[i], pkplr.pName);
684-
const bool hasSaveGame = ArchiveContainsGame(*archive);
685-
if (hasSaveGame)
686-
pkplr.bIsHellfire = gbIsHellfireSaveGame ? 1 : 0;
687-
688-
Player &player = Players[0];
689-
690-
UnPackPlayer(pkplr, player);
691-
// Temporarily set gSaveNumber to the save we're reading from
692-
// so that LoadHeroItems reads items from the correct save file
693-
gSaveNumber = i;
694-
LoadHeroItems(player);
695-
RemoveAllInvalidItems(player);
696-
CalcPlrInv(player, false);
697-
698-
Game2UiPlayer(player, &uihero, hasSaveGame);
699-
uiAddHeroInfo(&uihero);
700-
}
701-
}
682+
if (!archive)
683+
continue;
684+
PlayerPack pkplr;
685+
if (!ReadHero(*archive, &pkplr))
686+
continue;
687+
_uiheroinfo uihero;
688+
uihero.saveNumber = i;
689+
strcpy(hero_names[i], pkplr.pName);
690+
const bool hasSaveGame = ArchiveContainsGame(*archive);
691+
if (hasSaveGame)
692+
pkplr.bIsHellfire = gbIsHellfireSaveGame ? 1 : 0;
693+
694+
// Must unpack into Players[0]: InitPlayer/UnPackPlayer use Player::getId() (distance
695+
// from &Players[0]) for vision/lighting; a stack Player yields an invalid index.
696+
Player &player = Players[0];
697+
698+
UnPackPlayer(pkplr, player);
699+
// Temporarily set gSaveNumber to the save we're reading from
700+
// so that LoadHeroItems reads items from the correct save file
701+
gSaveNumber = i;
702+
LoadHeroItems(player);
703+
RemoveAllInvalidItems(player);
704+
CalcPlrInv(player, false);
705+
706+
Game2UiPlayer(player, &uihero, hasSaveGame);
707+
fn(&uihero);
702708
}
703709
gSaveNumber = originalSaveNumber;
704710

705711
return true;
706712
}
707713

714+
} // namespace
715+
716+
bool pfile_ui_set_hero_infos(bool (*uiAddHeroInfo)(_uiheroinfo *))
717+
{
718+
return pfile_ui_set_hero_infos_impl([uiAddHeroInfo](_uiheroinfo *h) { return uiAddHeroInfo(h); });
719+
}
720+
721+
bool pfile_ui_set_hero_infos(std::function<bool(_uiheroinfo *)> uiAddHeroInfo)
722+
{
723+
return pfile_ui_set_hero_infos_impl(std::move(uiAddHeroInfo));
724+
}
725+
708726
void pfile_ui_set_class_stats(HeroClass playerClass, _uidefaultstats *classStats)
709727
{
710728
const ClassAttributes &classAttributes = GetClassAttributes(playerClass);

Source/pfile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#pragma once
77

88
#include <cstdint>
9+
#include <functional>
910
#include <string>
1011

1112
#include <expected.hpp>
@@ -119,6 +120,7 @@ HeroCompareResult pfile_compare_hero_demo(int demo, bool logDetails);
119120

120121
void sfile_write_stash();
121122
bool pfile_ui_set_hero_infos(bool (*uiAddHeroInfo)(_uiheroinfo *));
123+
bool pfile_ui_set_hero_infos(std::function<bool(_uiheroinfo *)> uiAddHeroInfo);
122124
void pfile_ui_set_class_stats(HeroClass playerClass, _uidefaultstats *classStats);
123125
uint32_t pfile_ui_get_first_unused_save_num();
124126
bool pfile_ui_save_create(_uiheroinfo *heroinfo);

Source/stores.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ void SmithEnter()
13261326
StartStore(TalkID::SmithRepair);
13271327
break;
13281328
case 20:
1329-
CloseStore();
1329+
CloseLocalCoopStore();
13301330
break;
13311331
}
13321332
}
@@ -1560,7 +1560,7 @@ void WitchEnter()
15601560
StartStore(TalkID::WitchRecharge);
15611561
break;
15621562
case 20:
1563-
CloseStore();
1563+
CloseLocalCoopStore();
15641564
break;
15651565
}
15661566
}
@@ -1703,7 +1703,7 @@ void BoyEnter()
17031703
}
17041704

17051705
if ((CurrentTextLine != 8 && !BoyItem.isEmpty()) || (CurrentTextLine != 12 && BoyItem.isEmpty())) {
1706-
CloseStore();
1706+
CloseLocalCoopStore();
17071707
return;
17081708
}
17091709

@@ -1757,7 +1757,7 @@ void HealerBuyItem(Item &item)
17571757
void BoyBuyEnter()
17581758
{
17591759
if (CurrentTextLine != 10) {
1760-
CloseStore();
1760+
CloseLocalCoopStore();
17611761
return;
17621762
}
17631763

@@ -1882,7 +1882,7 @@ void HealerEnter()
18821882
}
18831883
break;
18841884
case 18:
1885-
CloseStore();
1885+
CloseLocalCoopStore();
18861886
break;
18871887
}
18881888
}
@@ -1928,7 +1928,7 @@ void StorytellerEnter()
19281928
StartStore(TalkID::StorytellerIdentify);
19291929
break;
19301930
case 18:
1931-
CloseStore();
1931+
CloseLocalCoopStore();
19321932
break;
19331933
}
19341934
}
@@ -2004,7 +2004,7 @@ void TavernEnter()
20042004
StartStore(TalkID::Gossip);
20052005
break;
20062006
case 18:
2007-
CloseStore();
2007+
CloseLocalCoopStore();
20082008
break;
20092009
}
20102010
}
@@ -2019,7 +2019,7 @@ void BarmaidEnter()
20192019
StartStore(TalkID::Gossip);
20202020
break;
20212021
case 14:
2022-
CloseStore();
2022+
CloseLocalCoopStore();
20232023
IsStashOpen = true;
20242024
Stash.RefreshItemStatFlags();
20252025
invflag = true;
@@ -2030,7 +2030,7 @@ void BarmaidEnter()
20302030
}
20312031
break;
20322032
case 18:
2033-
CloseStore();
2033+
CloseLocalCoopStore();
20342034
break;
20352035
}
20362036
}
@@ -2045,7 +2045,7 @@ void DrunkEnter()
20452045
StartStore(TalkID::Gossip);
20462046
break;
20472047
case 18:
2048-
CloseStore();
2048+
CloseLocalCoopStore();
20492049
break;
20502050
}
20512051
}
@@ -2145,7 +2145,7 @@ void AddStoreHoldRepair(Item *itm, int8_t i)
21452145
void InitStores()
21462146
{
21472147
ClearSText(0, NumStoreLines);
2148-
CloseStore();
2148+
CloseLocalCoopStore();
21492149
IsTextFullSize = false;
21502150
HasScrollbar = false;
21512151
PremiumItemCount = 0;
@@ -2186,7 +2186,7 @@ void FreeStoreMem()
21862186
if (*GetOptions().Gameplay.showItemGraphicsInStores) {
21872187
FreeHalfSizeItemSprites();
21882188
}
2189-
CloseStore();
2189+
CloseLocalCoopStore();
21902190
for (STextStruct &entry : TextLine) {
21912191
entry.text.clear();
21922192
entry.text.shrink_to_fit();
@@ -2498,7 +2498,7 @@ void StoreESC()
24982498
case TalkID::Tavern:
24992499
case TalkID::Drunk:
25002500
case TalkID::Barmaid:
2501-
CloseStore();
2501+
CloseLocalCoopStore();
25022502
break;
25032503
case TalkID::Gossip:
25042504
StartStore(OldActiveStore);

0 commit comments

Comments
 (0)