Skip to content

Commit

Permalink
Merge branch 'main' into prod
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsSammyM committed Dec 29, 2024
2 parents 2cb5027 + 6509f04 commit 8dedcea
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import { GameModeContext } from "./GameModesEditor";
import { Button } from "../Button";

export function EnabledModifiersSelector(props: Readonly<{
disabled: boolean,
disabled?: boolean,
enabledModifiers?: ModifierType[],
onChange?: (modifiers: ModifierType[]) => void,
}>): ReactElement {
let { enabledModifiers } = useContext(GameModeContext);
enabledModifiers = props.enabledModifiers ?? enabledModifiers;


return <div className="chat-menu-colors selector-section">
<h2>{translate("modifiers")}</h2>
<EnabledModifiersDisplay
disabled={props.disabled}
disabled={props.disabled===undefined ? false : props.disabled}
modifiable={!props.disabled}
enabledModifiers={enabledModifiers}
onEnableModifiers={(modifiers: ModifierType[]) => {
Expand Down
12 changes: 6 additions & 6 deletions client/src/components/gameModeSettings/GameModeSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ReactElement, useCallback, useContext, useEffect, useState } from "react";
import { deleteGameModes, loadGameModes, saveGameModes } from "../../game/localStorage";
import { deleteGameModes, loadGameModesParsed, saveGameModes } from "../../game/localStorage";
import { AnchorControllerContext } from "../../menu/Anchor";
import { CopyButton, PasteButton } from "../../components/ClipboardButtons";
import Icon from "../Icon";
Expand All @@ -21,7 +21,7 @@ export function GameModeSelector(props: {
canModifySavedGameModes?: boolean,
loadGameMode: (gameMode: GameModeData) => void,
}): ReactElement {
const [gameModeParseResult, setGameModeParseResult] = useState(parseFromJson("GameModeStorage", loadGameModes()));
const [gameModeParseResult, setGameModeParseResult] = useState(loadGameModesParsed());

return <section className="chat-menu-colors selector-section">
<h2>{translate("menu.lobby.gameModes")}</h2>
Expand All @@ -32,16 +32,16 @@ export function GameModeSelector(props: {
<br />
<code>{gameModeParseResult.toString()}</code>
</div>
<button onClick={() => {
<Button onClick={() => {
deleteGameModes();
setGameModeParseResult(parseFromJson("GameModeStorage", loadGameModes()));
setGameModeParseResult(loadGameModesParsed());
}}>
<Icon>delete</Icon>{translate("deleteOutdatedGameModeSaveData")}
</button>
</Button>
</div>
: <GameModeSelectorPanel {...props}
gameModeStorage={gameModeParseResult.value}
reloadGameModeStorage={() => setGameModeParseResult(parseFromJson("GameModeStorage", loadGameModes()))}
reloadGameModeStorage={() => setGameModeParseResult(loadGameModesParsed())}
/>
}
</section>
Expand Down
2 changes: 1 addition & 1 deletion client/src/game/gameManager.d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type Server = {
close(): void;
}

export type StateEventType = ToClientPacket["type"] | "tick" | "filterUpdate";
export type StateEventType = ToClientPacket["type"] | "tick" | "filterUpdate" | "openGameMenu" | "closeGameMenu" | "whisperChatOpenOrClose";
export type StateListener = (type?: StateEventType) => void;

export type GameManager = {
Expand Down
2 changes: 2 additions & 0 deletions client/src/game/gameState.d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ type GameState = {
clientState: PlayerGameState | {type: "spectator"},
host: boolean,

missedChatMessages: boolean,
missedWhispers: PlayerIndex[]
}
export default GameState;

Expand Down
4 changes: 3 additions & 1 deletion client/src/game/gameState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ export function createGameState(): GameState {
ticking: true,

clientState: createPlayerGameState(),
host: false
host: false,

missedChatMessages: false,
missedWhispers: [],
}
}

Expand Down
53 changes: 31 additions & 22 deletions client/src/game/localStorage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Language } from "./lang";
import { Role } from "./roleState.d";
import parseFromJson from "../components/gameModeSettings/gameMode/dataFixer";
import { ContentMenu } from "../menu/game/GameScreen";
import { ParseResult, Success } from "../components/gameModeSettings/gameMode/parse";


export function saveReconnectData(roomCode: number, playerId: number) {
localStorage.setItem(
Expand Down Expand Up @@ -67,7 +69,26 @@ export function loadSettingsParsed(): Settings {
return result.value;
}
}

export function getDefaultSettings(): Readonly<Settings> {
return {
format: "v3",
volume: 0.5,
fontSize: 1,
accessibilityFont: false,
language: "en_us",
defaultName: null,
maxMenus: window.innerWidth < 600 ? 1 : 6,
menuOrder: [
ContentMenu.WikiMenu,
ContentMenu.GraveyardMenu,
ContentMenu.PlayerListMenu,
ContentMenu.ChatMenu,
ContentMenu.WillMenu,
ContentMenu.RoleSpecificMenu
],
roleSpecificMenus: []
}
}
export function loadSettings(): unknown {
const data = localStorage.getItem("settings");
if (data !== null) {
Expand Down Expand Up @@ -96,13 +117,21 @@ export function saveSettings(newSettings: Partial<Settings>) {
}
}

let cachedGameModes: ParseResult<GameModeStorage> | null = null;

export function loadGameModesParsed(): ParseResult<GameModeStorage> {

if(cachedGameModes !== null) return cachedGameModes;

cachedGameModes = parseFromJson("GameModeStorage", loadGameModes());
return cachedGameModes;
}
export function defaultGameModes(): unknown {
// Typescript is a Division One tweaker
return DEFAULT_GAME_MODES;
}

export function saveGameModes(gameModes: GameModeStorage) {
cachedGameModes = Success(gameModes);
localStorage.setItem("savedGameModes", JSON.stringify(gameModes));
}
export function loadGameModes(): unknown {
Expand All @@ -120,23 +149,3 @@ export function deleteGameModes() {
localStorage.removeItem("savedGameModes");
}

export function getDefaultSettings(): Readonly<Settings> {
return {
format: "v3",
volume: 0.5,
fontSize: 1,
accessibilityFont: false,
language: "en_us",
defaultName: null,
maxMenus: window.innerWidth < 600 ? 1 : 6,
menuOrder: [
ContentMenu.WikiMenu,
ContentMenu.GraveyardMenu,
ContentMenu.PlayerListMenu,
ContentMenu.ChatMenu,
ContentMenu.WillMenu,
ContentMenu.RoleSpecificMenu
],
roleSpecificMenus: []
}
}
11 changes: 11 additions & 0 deletions client/src/game/messageListener.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,17 @@ export default function messageListener(packet: ToClientPacket){
if(GAME_MANAGER.state.stateType === "game" || GAME_MANAGER.state.stateType === "lobby"){
GAME_MANAGER.state.chatMessages = GAME_MANAGER.state.chatMessages.concat(packet.chatMessages);

// Chat notification icon state
if(GAME_MANAGER.state.stateType === "game" && packet.chatMessages.length !== 0){
GAME_MANAGER.state.missedChatMessages = true;

for(let chatMessage of packet.chatMessages){
if(chatMessage.variant.type === "whisper"){
GAME_MANAGER.state.missedWhispers.push(chatMessage.variant.fromPlayerIndex);
}
}
}

for(let chatMessage of packet.chatMessages){
let audioSrc = chatMessageToAudio(chatMessage);
if(audioSrc)
Expand Down
18 changes: 15 additions & 3 deletions client/src/menu/game/GameScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ export function useMenuController<C extends Partial<Record<ContentMenu, boolean>
setMenuController({
closeMenu(menu) {
setContentMenu(menu, false)

if (GAME_MANAGER.state.stateType === "game" && menu === ContentMenu.ChatMenu){
GAME_MANAGER.state.missedChatMessages = false;
}
GAME_MANAGER.invokeStateListeners("closeGameMenu");
},
closeOrOpenMenu(menu) {
if (getMenuController().menusOpen().includes(menu)) {
Expand All @@ -127,10 +132,16 @@ export function useMenuController<C extends Partial<Record<ContentMenu, boolean>
},
openMenu(menu, callback) {
setContentMenu(menu, true);


if (GAME_MANAGER.state.stateType === "game" && menu === ContentMenu.ChatMenu){
GAME_MANAGER.state.missedChatMessages = false;
}

if (callback) {
setCallbacks(callbacks => callbacks.concat(callback))
}

GAME_MANAGER.invokeStateListeners("openGameMenu");
},
menusOpen(): ContentMenu[] {
return Object.entries(contentMenus)
Expand Down Expand Up @@ -190,9 +201,10 @@ export default function GameScreen(): ReactElement {
);

const chatMenuNotification = useGameState(
() => !menuController.menusOpen().includes(ContentMenu.ChatMenu),
["addChatMessages"]
(game) => game.missedChatMessages && !menuController.menuOpen(ContentMenu.ChatMenu),
["addChatMessages", "openGameMenu", "closeGameMenu"]
)!;


useEffect(() => {
const onBeforeUnload = (e: BeforeUnloadEvent) => {
Expand Down
16 changes: 15 additions & 1 deletion client/src/menu/game/gameScreenContent/PlayerListMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ function PlayerCard(props: Readonly<{
["addGrave"]
)!

const whisperNotification = useGameState(
gameState =>
gameState.missedWhispers.some(player => player === props.playerIndex) &&
!isPlayerSelf &&
!whisperChatOpen,
["addChatMessages", "whisperChatOpenOrClose"]
);

return <><div
className={`player-card`}
key={props.playerIndex}
Expand Down Expand Up @@ -174,10 +182,16 @@ function PlayerCard(props: Readonly<{
onClick={()=>{
// GAME_MANAGER.prependWhisper(props.playerIndex); return true;
setWhisperChatOpen(!whisperChatOpen);
if(GAME_MANAGER.state.stateType === 'game'){
GAME_MANAGER.state.missedWhispers =
GAME_MANAGER.state.missedWhispers.filter(player => player !== props.playerIndex);
}
GAME_MANAGER.invokeStateListeners("whisperChatOpenOrClose");
}}
pressedChildren={() => <Icon>done</Icon>}
>
{whisperChatOpen?<Icon>close</Icon>:<Icon>chat</Icon>}
{whisperChatOpen===true?<Icon>close</Icon>:<Icon>chat</Icon>}
{whisperNotification===true && <div className="chat-notification highlighted">!</div>}
</Button>
}
{GAME_MANAGER.getMySpectator() || (() => {
Expand Down
18 changes: 18 additions & 0 deletions client/src/menu/game/gameScreenContent/playerListMenu.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
align-items: center;

padding: 0 .13rem;
position: relative;
}
.player-card > button{
position: relative;
}
.player-card > .player-name-plate {
flex-grow: 1;
Expand All @@ -66,4 +70,18 @@
}
.player-list-menu .player-card-holder:nth-last-child(odd) {
background-color: var(--secondary-color);
}

.player-card .chat-notification{
font-size: 0.83rem;
height: 0.83rem;
aspect-ratio: 1;
background-color: var(--primary-color);
position: absolute;
padding: 0;
border-width: .13rem;
border-style: solid;
border-radius: 50%;
top: 0;
right: 0;
}
2 changes: 1 addition & 1 deletion client/src/menu/lobby/LobbyMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function LobbyMenuSettings(props: Readonly<{

return <GameModeContext.Provider value={context}>
{mobile && <h1>{translate("menu.lobby.settings")}</h1>}
{props.isHost && <GameModeSelector
{props.isHost === true && <GameModeSelector
canModifySavedGameModes={false}
loadGameMode={gameMode => {
GAME_MANAGER.sendSetPhaseTimesPacket(gameMode.phaseTimes);
Expand Down
9 changes: 9 additions & 0 deletions client/src/resources/abilityId.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@
"role/spiral/0": {
"midnight": true
},
"role/warden/0": {
"midnight": false
},
"role/warden/1": {
"midnight": true
},
"wardenLiveOrDie": {
"midnight": true
},
"role/kira/0": {
"midnight": true
},
Expand Down
1 change: 1 addition & 0 deletions client/src/resources/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@
"role.impostor.name:var.0": "Impostors",
"role.impostor.name:var.1": "Imposter",
"role.impostor.name:var.2": "Imposters",
"role.impostor.name:var.3": "",
"controllerId.role.impostor.0.name": "Attack",
"controllerId.role.impostor.1.name": "Disguise",

Expand Down
8 changes: 5 additions & 3 deletions server/src/game/role/krampus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ impl RoleStateImpl for Krampus {
if let Some(visit) = actor_visits.first() {
let target_ref = visit.target;

actor_ref.add_private_chat_messages(game, vec![
ChatMessageVariant::TargetHasRole { role: target_ref.role(game) },
actor_ref.push_night_message(game,
ChatMessageVariant::TargetHasRole { role: target_ref.role(game) }
);
actor_ref.push_night_message(game,
ChatMessageVariant::TargetHasWinCondition { win_condition: target_ref.win_condition(game).clone() }
]);
);
}
}
_ => {}
Expand Down
6 changes: 3 additions & 3 deletions server/src/game/role/santa_claus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl RoleStateImpl for SantaClaus {
win_if_any.insert(GameConclusion::NiceList);
target_ref.set_win_condition(game, WinCondition::GameConclusionReached { win_if_any });

target_ref.add_private_chat_message(game, ChatMessageVariant::AddedToNiceList);
target_ref.push_night_message(game, ChatMessageVariant::AddedToNiceList);
actor_ref.set_role_state(game, Self {
ability_used_last_night: Some(SantaListKind::Nice),
..self
Expand All @@ -78,10 +78,10 @@ impl RoleStateImpl for SantaClaus {
.collect();

if !krampus_list.is_empty() {
target_ref.add_private_chat_message(game, ChatMessageVariant::AddedToNaughtyList);
target_ref.push_night_message(game, ChatMessageVariant::AddedToNaughtyList);
}
for krampus in krampus_list {
krampus.add_private_chat_message(game,
krampus.push_night_message(game,
ChatMessageVariant::SantaAddedPlayerToNaughtyList { player: target_ref }
);
}
Expand Down

0 comments on commit 8dedcea

Please sign in to comment.