diff options
author | Sergeanur <s.anureev@yandex.ua> | 2021-01-02 11:50:28 +0100 |
---|---|---|
committer | Sergeanur <s.anureev@yandex.ua> | 2021-01-02 11:51:09 +0100 |
commit | e7c46ac6587f664ee0531af8e1dd1159fe738979 (patch) | |
tree | 4e40b4ad6602fcdb1d1b392611bcd3772d8b2ec1 | |
parent | increase screen droplet splash dist (diff) | |
download | re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar.gz re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar.bz2 re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar.lz re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar.xz re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.tar.zst re3-e7c46ac6587f664ee0531af8e1dd1159fe738979.zip |
Diffstat (limited to '')
-rw-r--r-- | src/core/ControllerConfig.cpp | 86 | ||||
-rw-r--r-- | src/render/Font.cpp | 67 | ||||
-rw-r--r-- | src/render/Font.h | 4 |
3 files changed, 104 insertions, 53 deletions
diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index fe865865..b2dad358 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2354,15 +2354,15 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act #define VFB(b) #endif -#define CONTROLLER_BUTTONS(T, O, X, Q, L1, L2, L3, R1, R2, R3, SELECT) \ +#define CONTROLLER_BUTTONS(T, O, X, Q, L1, L2, L3, R1, R2, R3, SELECT, RSL, RSR) \ {{ \ O, /* PED_FIREWEAPON */ \ R2, /* PED_CYCLE_WEAPON_RIGHT */ \ L2, /* PED_CYCLE_WEAPON_LEFT */ \ nil, /* GO_FORWARD */ \ nil, /* GO_BACK */ \ - nil, /* GO_LEFT */ \ - nil, /* GO_RIGHT */ \ + LEFT, /* GO_LEFT */ \ + RIGHT, /* GO_RIGHT */ \ Q, /* PED_SNIPER_ZOOM_IN */ \ X, /* PED_SNIPER_ZOOM_OUT */ \ T, /* VEHICLE_ENTER_EXIT */ \ @@ -2370,6 +2370,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act Q, /* PED_JUMPING */ \ X, /* PED_SPRINT */ \ R3, /* PED_LOOKBEHIND */ \ + L3, /* PED_DUCK */ \ + L1, /* PED_ANSWER_PHONE */ \ VFB(O) /* VEHICLE_FIREWEAPON */ \ X, /* VEHICLE_ACCELERATE */ \ Q, /* VEHICLE_BRAKE */ \ @@ -2382,10 +2384,10 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* VEHICLE_LOOKLEFT */ \ R2, /* VEHICLE_LOOKRIGHT */ \ nil, /* VEHICLE_LOOKBEHIND */ \ - nil, /* VEHICLE_TURRETLEFT */ \ - nil, /* VEHICLE_TURRETRIGHT */ \ - nil, /* VEHICLE_TURRETUP */ \ - nil, /* VEHICLE_TURRETDOWN */ \ + RSL, /* VEHICLE_TURRETLEFT */ \ + RSR, /* VEHICLE_TURRETRIGHT */ \ + UP, /* VEHICLE_TURRETUP */ \ + DOWN, /* VEHICLE_TURRETDOWN */ \ L2, /* PED_CYCLE_TARGET_LEFT */ \ R2, /* PED_CYCLE_TARGET_RIGHT */ \ L1, /* PED_CENTER_CAMERA_BEHIND_PLAYER */ \ @@ -2397,6 +2399,7 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act nil, /* TOGGLE_DPAD */ \ nil, /* SWITCH_DEBUG_CAM_ON */ \ nil, /* TAKE_SCREEN_SHOT */ \ + nil, /* UNKNOWN_ACTION */ \ nil, /* SHOW_MOUSE_POINTER_TOGGLE */ \ }, \ { \ @@ -2405,8 +2408,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* PED_CYCLE_WEAPON_LEFT */ \ nil, /* GO_FORWARD */ \ nil, /* GO_BACK */ \ - nil, /* GO_LEFT */ \ - nil, /* GO_RIGHT */ \ + LEFT, /* GO_LEFT */ \ + RIGHT, /* GO_RIGHT */ \ Q, /* PED_SNIPER_ZOOM_IN */ \ X, /* PED_SNIPER_ZOOM_OUT */ \ T, /* VEHICLE_ENTER_EXIT */ \ @@ -2414,6 +2417,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act Q, /* PED_JUMPING */ \ X, /* PED_SPRINT */ \ R3, /* PED_LOOKBEHIND */ \ + L3, /* PED_DUCK */ \ + L1, /* PED_ANSWER_PHONE */ \ VFB(O) /* VEHICLE_FIREWEAPON */ \ X, /* VEHICLE_ACCELERATE */ \ Q, /* VEHICLE_BRAKE */ \ @@ -2426,10 +2431,10 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* VEHICLE_LOOKLEFT */ \ R2, /* VEHICLE_LOOKRIGHT */ \ nil, /* VEHICLE_LOOKBEHIND */ \ - nil, /* VEHICLE_TURRETLEFT */ \ - nil, /* VEHICLE_TURRETRIGHT */ \ - nil, /* VEHICLE_TURRETUP */ \ - nil, /* VEHICLE_TURRETDOWN */ \ + RSL, /* VEHICLE_TURRETLEFT */ \ + RSR, /* VEHICLE_TURRETRIGHT */ \ + UP, /* VEHICLE_TURRETUP */ \ + DOWN, /* VEHICLE_TURRETDOWN */ \ L2, /* PED_CYCLE_TARGET_LEFT */ \ R2, /* PED_CYCLE_TARGET_RIGHT */ \ L1, /* PED_CENTER_CAMERA_BEHIND_PLAYER */ \ @@ -2441,6 +2446,7 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act nil, /* TOGGLE_DPAD */ \ nil, /* SWITCH_DEBUG_CAM_ON */ \ nil, /* TAKE_SCREEN_SHOT */ \ + nil, /* UNKNOWN_ACTION */ \ nil, /* SHOW_MOUSE_POINTER_TOGGLE */ \ }, \ { \ @@ -2449,8 +2455,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* PED_CYCLE_WEAPON_LEFT */ \ nil, /* GO_FORWARD */ \ nil, /* GO_BACK */ \ - nil, /* GO_LEFT */ \ - nil, /* GO_RIGHT */ \ + LEFT, /* GO_LEFT */ \ + RIGHT, /* GO_RIGHT */ \ T, /* PED_SNIPER_ZOOM_IN */ \ Q, /* PED_SNIPER_ZOOM_OUT */ \ L1, /* VEHICLE_ENTER_EXIT */ \ @@ -2458,6 +2464,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act Q, /* PED_JUMPING */ \ O, /* PED_SPRINT */ \ R3, /* PED_LOOKBEHIND */ \ + L3, /* PED_DUCK */ \ + L1, /* PED_ANSWER_PHONE */ \ VFB(O) /* VEHICLE_FIREWEAPON */ \ X, /* VEHICLE_ACCELERATE */ \ Q, /* VEHICLE_BRAKE */ \ @@ -2470,10 +2478,10 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* VEHICLE_LOOKLEFT */ \ R2, /* VEHICLE_LOOKRIGHT */ \ nil, /* VEHICLE_LOOKBEHIND */ \ - nil, /* VEHICLE_TURRETLEFT */ \ - nil, /* VEHICLE_TURRETRIGHT */ \ - nil, /* VEHICLE_TURRETUP */ \ - nil, /* VEHICLE_TURRETDOWN */ \ + RSL, /* VEHICLE_TURRETLEFT */ \ + RSR, /* VEHICLE_TURRETRIGHT */ \ + UP, /* VEHICLE_TURRETUP */ \ + DOWN, /* VEHICLE_TURRETDOWN */ \ L2, /* PED_CYCLE_TARGET_LEFT */ \ R2, /* PED_CYCLE_TARGET_RIGHT */ \ T, /* PED_CENTER_CAMERA_BEHIND_PLAYER */ \ @@ -2485,6 +2493,7 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act nil, /* TOGGLE_DPAD */ \ nil, /* SWITCH_DEBUG_CAM_ON */ \ nil, /* TAKE_SCREEN_SHOT */ \ + nil, /* UNKNOWN_ACTION */ \ nil, /* SHOW_MOUSE_POINTER_TOGGLE */ \ }, \ { \ @@ -2493,8 +2502,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* PED_CYCLE_WEAPON_LEFT */ \ nil, /* GO_FORWARD */ \ nil, /* GO_BACK */ \ - nil, /* GO_LEFT */ \ - nil, /* GO_RIGHT */ \ + LEFT, /* GO_LEFT */ \ + RIGHT, /* GO_RIGHT */ \ Q, /* PED_SNIPER_ZOOM_IN */ \ X, /* PED_SNIPER_ZOOM_OUT */ \ T, /* VEHICLE_ENTER_EXIT */ \ @@ -2502,6 +2511,8 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act Q, /* PED_JUMPING */ \ X, /* PED_SPRINT */ \ R3, /* PED_LOOKBEHIND */ \ + L3, /* PED_DUCK */ \ + L1, /* PED_ANSWER_PHONE */ \ VFB(R1) /* VEHICLE_FIREWEAPON */ \ nil, /* VEHICLE_ACCELERATE */ \ nil, /* VEHICLE_BRAKE */ \ @@ -2514,10 +2525,10 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act L2, /* VEHICLE_LOOKLEFT */ \ R2, /* VEHICLE_LOOKRIGHT */ \ nil, /* VEHICLE_LOOKBEHIND */ \ - nil, /* VEHICLE_TURRETLEFT */ \ - nil, /* VEHICLE_TURRETRIGHT */ \ - nil, /* VEHICLE_TURRETUP */ \ - nil, /* VEHICLE_TURRETDOWN */ \ + RSL, /* VEHICLE_TURRETLEFT */ \ + RSR, /* VEHICLE_TURRETRIGHT */ \ + UP, /* VEHICLE_TURRETUP */ \ + DOWN, /* VEHICLE_TURRETDOWN */ \ L2, /* PED_CYCLE_TARGET_LEFT */ \ R2, /* PED_CYCLE_TARGET_RIGHT */ \ O, /* PED_CENTER_CAMERA_BEHIND_PLAYER */ \ @@ -2529,14 +2540,26 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act nil, /* TOGGLE_DPAD */ \ nil, /* SWITCH_DEBUG_CAM_ON */ \ nil, /* TAKE_SCREEN_SHOT */ \ + nil, /* UNKNOWN_ACTION */ \ nil, /* SHOW_MOUSE_POINTER_TOGGLE */ \ }} +#ifdef BUTTON_ICONS +#define UP "~U~" +#define DOWN "~D~" +#define LEFT "~<~" +#define RIGHT "~>~" +#else +#define UP "UP" +#define DOWN "DOWN" +#define LEFT "LEFT" +#define RIGHT "RIGHT" +#endif -const char *XboxButtons_noIcons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("Y", "B", "A", "X", "LB", "LT", "LS", "RB", "RT", "RS", "BACK"); +const char *XboxButtons_noIcons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("Y", "B", "A", "X", "LB", "LT", "LS", "RB", "RT", "RS", "BACK", "right stick left", "right stick right"); #ifdef BUTTON_ICONS -const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("~T~", "~O~", "~X~", "~Q~", "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "BACK"); +const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("~T~", "~O~", "~X~", "~Q~", "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "BACK", "~(~", "~)~"); #endif @@ -2558,11 +2581,11 @@ const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("~T~", "~O #endif const char *PlayStationButtons_noIcons[][MAX_CONTROLLERACTIONS] = - CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "L1", "L2", "L3", "R1", "R2", "R3", "SELECT"); + CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "L1", "L2", "L3", "R1", "R2", "R3", "SELECT", "right stick left", "right stick right"); #ifdef BUTTON_ICONS const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = - CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "SELECT"); + CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "SELECT", "~(~", "~)~"); #endif #undef PS2_TRIANGLE @@ -2570,6 +2593,11 @@ const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = #undef PS2_CROSS #undef PS2_SQUARE +#undef UP +#undef DOWN +#undef LEFT +#undef RIGHT + #undef CONTROLLER_BUTTONS #undef VFB diff --git a/src/render/Font.cpp b/src/render/Font.cpp index d6a06db8..3517031d 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -297,12 +297,10 @@ CFont::Initialise(void) CTxdStore::AddRef(ButtonsSlot); CTxdStore::PushCurrentTxd(); CTxdStore::SetCurrentTxd(ButtonsSlot); -#if 0 // unused - ButtonSprite[BUTTON_UP].SetTexture("up"); - ButtonSprite[BUTTON_DOWN].SetTexture("down"); - ButtonSprite[BUTTON_LEFT].SetTexture("left"); - ButtonSprite[BUTTON_RIGHT].SetTexture("right"); -#endif + ButtonSprite[BUTTON_UP].SetTexture("thumblyu"); + ButtonSprite[BUTTON_DOWN].SetTexture("thumblyd"); + ButtonSprite[BUTTON_LEFT].SetTexture("thumblxl"); + ButtonSprite[BUTTON_RIGHT].SetTexture("thumblxr"); ButtonSprite[BUTTON_CROSS].SetTexture("cross"); ButtonSprite[BUTTON_CIRCLE].SetTexture("circle"); ButtonSprite[BUTTON_SQUARE].SetTexture("square"); @@ -313,6 +311,8 @@ CFont::Initialise(void) ButtonSprite[BUTTON_R1].SetTexture("r1"); ButtonSprite[BUTTON_R2].SetTexture("r2"); ButtonSprite[BUTTON_R3].SetTexture("r3"); + ButtonSprite[BUTTON_RSTICK_LEFT].SetTexture("thumbrxl"); + ButtonSprite[BUTTON_RSTICK_RIGHT].SetTexture("thumbrxr"); CTxdStore::PopCurrentTxd(); } #endif // BUTTON_ICONS @@ -411,9 +411,12 @@ CFont::DrawButton(float x, float y) rect.bottom = Details.scaleY * 19.0f + y; int vertexAlphaState; + void *raster; RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &vertexAlphaState); + RwRenderStateGet(rwRENDERSTATETEXTURERASTER, &raster); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); ButtonSprite[PS2Symbol].Draw(rect, CRGBA(255, 255, 255, Details.color.a)); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, raster); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)vertexAlphaState); } } @@ -926,14 +929,6 @@ CFont::PrintString(float x, float y, wchar *start, wchar *&end, float spwidth, f if (Details.slant != 0.0f && !IsJapanese()) y = (Details.slantRefX - x) * Details.slant + Details.slantRefY; -#ifdef BUTTON_ICONS - if (PS2Symbol != BUTTON_NONE) { - DrawButton(x, y); - x += Details.scaleY * 17.0f; - PS2Symbol = BUTTON_NONE; - } -#endif - PrintChar(x, y, c); x += GetCharacterSize(c); if (c == 0 && (!NewLine || !IsJapanese())) // space @@ -1132,12 +1127,10 @@ CFont::GetStringWidth(wchar *s, bool spaces) s++; #ifdef BUTTON_ICONS switch (*s) { -#if 0 // unused case 'U': case 'D': case '<': case '>': -#endif case 'X': case 'O': case 'Q': @@ -1148,6 +1141,8 @@ CFont::GetStringWidth(wchar *s, bool spaces) case 'J': case 'V': case 'C': + case '(': + case ')': w += 17.0f * Details.scaleY; break; default: @@ -1170,12 +1165,10 @@ CFont::GetStringWidth(wchar *s, bool spaces) s++; #ifdef BUTTON_ICONS switch (*s) { -#if 0 // unused case 'U': case 'D': case '<': case '>': -#endif case 'X': case 'O': case 'Q': @@ -1186,6 +1179,8 @@ CFont::GetStringWidth(wchar *s, bool spaces) case 'J': case 'V': case 'C': + case '(': + case ')': w += 17.0f * Details.scaleY; break; default: @@ -1280,12 +1275,10 @@ CFont::ParseToken(wchar *s, bool japShit) case 'w': SetColor(CRGBA(175, 175, 175, 255)); break; case 'y': SetColor(CRGBA(210, 196, 106, 255)); break; #ifdef BUTTON_ICONS -#if 0 // unused case 'U': PS2Symbol = BUTTON_UP; break; case 'D': PS2Symbol = BUTTON_DOWN; break; case '<': PS2Symbol = BUTTON_LEFT; break; case '>': PS2Symbol = BUTTON_RIGHT; break; -#endif case 'X': PS2Symbol = BUTTON_CROSS; break; case 'O': PS2Symbol = BUTTON_CIRCLE; break; case 'Q': PS2Symbol = BUTTON_SQUARE; break; @@ -1296,6 +1289,8 @@ CFont::ParseToken(wchar *s, bool japShit) case 'J': PS2Symbol = BUTTON_R1; break; case 'V': PS2Symbol = BUTTON_R2; break; case 'C': PS2Symbol = BUTTON_R3; break; + case '(': PS2Symbol = BUTTON_RSTICK_LEFT; break; + case ')': PS2Symbol = BUTTON_RSTICK_RIGHT; break; #endif } } else if (IsJapanese()) { @@ -1342,12 +1337,10 @@ CFont::ParseToken(wchar *s) #endif case 'y': SetColor(CRGBA(255, 227, 79, 255)); Details.anonymous_23 = true; break; #ifdef BUTTON_ICONS -#if 0 // unused case 'U': PS2Symbol = BUTTON_UP; break; case 'D': PS2Symbol = BUTTON_DOWN; break; case '<': PS2Symbol = BUTTON_LEFT; break; case '>': PS2Symbol = BUTTON_RIGHT; break; -#endif case 'X': PS2Symbol = BUTTON_CROSS; break; case 'O': PS2Symbol = BUTTON_CIRCLE; break; case 'Q': PS2Symbol = BUTTON_SQUARE; break; @@ -1358,6 +1351,8 @@ CFont::ParseToken(wchar *s) case 'J': PS2Symbol = BUTTON_R1; break; case 'V': PS2Symbol = BUTTON_R2; break; case 'C': PS2Symbol = BUTTON_R3; break; + case '(': PS2Symbol = BUTTON_RSTICK_LEFT; break; + case ')': PS2Symbol = BUTTON_RSTICK_RIGHT; break; #endif } while(*s != '~') s++; @@ -1450,6 +1445,24 @@ CFont::ParseToken(wchar* str, CRGBA &color, bool &flash, bool &bold) color.g = 227; color.b = 79; break; +#ifdef BUTTON_ICONS + case 'U': PS2Symbol = BUTTON_UP; break; + case 'D': PS2Symbol = BUTTON_DOWN; break; + case '<': PS2Symbol = BUTTON_LEFT; break; + case '>': PS2Symbol = BUTTON_RIGHT; break; + case 'X': PS2Symbol = BUTTON_CROSS; break; + case 'O': PS2Symbol = BUTTON_CIRCLE; break; + case 'Q': PS2Symbol = BUTTON_SQUARE; break; + case 'T': PS2Symbol = BUTTON_TRIANGLE; break; + case 'K': PS2Symbol = BUTTON_L1; break; + case 'M': PS2Symbol = BUTTON_L2; break; + case 'A': PS2Symbol = BUTTON_L3; break; + case 'J': PS2Symbol = BUTTON_R1; break; + case 'V': PS2Symbol = BUTTON_R2; break; + case 'C': PS2Symbol = BUTTON_R3; break; + case '(': PS2Symbol = BUTTON_RSTICK_LEFT; break; + case ')': PS2Symbol = BUTTON_RSTICK_RIGHT; break; +#endif default: break; } @@ -1503,7 +1516,17 @@ CFont::RenderFontBuffer() color = RenderState.color; } if (*pRenderStateBufPointer.pStr == '~') { +#ifdef BUTTON_ICONS + PS2Symbol = BUTTON_NONE; +#endif pRenderStateBufPointer.pStr = ParseToken(pRenderStateBufPointer.pStr, color, bFlash, bBold); +#ifdef BUTTON_ICONS + if(PS2Symbol != BUTTON_NONE) { + DrawButton(textPosX, textPosY); + textPosX += Details.scaleY * 17.0f; + PS2Symbol = BUTTON_NONE; + } +#endif if (bFlash) { if (CTimer::GetTimeInMilliseconds() - Details.nFlashTimer > 300) { Details.bFlashState = !Details.bFlashState; diff --git a/src/render/Font.h b/src/render/Font.h index d61ca6e7..36424bf5 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -95,12 +95,10 @@ enum enum { BUTTON_NONE = -1, -#if 0 // unused BUTTON_UP, BUTTON_DOWN, BUTTON_LEFT, BUTTON_RIGHT, -#endif BUTTON_CROSS, BUTTON_CIRCLE, BUTTON_SQUARE, @@ -111,6 +109,8 @@ enum BUTTON_R1, BUTTON_R2, BUTTON_R3, + BUTTON_RSTICK_LEFT, + BUTTON_RSTICK_RIGHT, MAX_BUTTON_ICONS }; #endif // BUTTON_ICONS |