+
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/common/components/card/CardStat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class CardStat extends React.Component<CardStatProps> {
textDecoration: 'line-through'
};

if (current && current !== base) {
if (isNumber(current) && current !== base) {
return (
<span style={{ position: 'relative' }}>
<span style={baseStatStyle}>
Expand Down
4 changes: 2 additions & 2 deletions src/common/components/game/Deck.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default class Deck extends React.Component<DeckProps> {
if (deck.length > 0) {
return (
<Tooltip
text={`${deck.length} Cards`}
style={{fontFamily: '"Carter One", "Carter One-fallback"'}}
text={`${deck.length} ${deck.length === 1 ? 'card' : 'cards'}`}
style={{ fontFamily: '"Carter One", "Carter One-fallback"' }}
>
<CardBack deckLength={deck.length} />
</Tooltip>
Expand Down
1 change: 1 addition & 0 deletions src/common/components/game/GameArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ export default class GameArea extends React.Component<GameAreaProps, GameAreaSta
return (
<Chat
inGame
inSandbox={isSandbox}
fullscreen={screenfull.isFullscreen}
open={chatOpen}
compact={compactControls}
Expand Down
5 changes: 4 additions & 1 deletion src/common/components/game/Sfx.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';

import { inBrowser, isFlagSet } from '../../util/browser';
import { inBrowser, isFlagSet, setFlagIfUnset } from '../../util/browser';

const Sound = inBrowser() ? require('react-sound').default : null;
const soundManager = inBrowser() ? require('soundmanager2/script/soundmanager2-nodebug').soundManager : null;
Expand All @@ -17,6 +17,9 @@ interface SfxState {
// hacky workaround to the fact that sfxQueue is actually mutable for card execution reasons
let CURRENT_SFX_QUEUE_LENGTH = 0;

// Default sound to true
setFlagIfUnset('sound', true);

export default class Sfx extends React.Component<SfxProps, SfxState> {
public state = {
idx: 0
Expand Down
24 changes: 14 additions & 10 deletions src/common/components/play/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ChatProps {
roomName: string | null
messages: w.ChatMessage[]
inGame?: boolean
inSandbox?: boolean
open?: boolean
compact?: boolean
fullscreen?: boolean
Expand All @@ -40,14 +41,17 @@ interface ChatState {
}

export default class Chat extends React.Component<ChatProps, ChatState> {
public state = {
chatFieldValue: '',
optionsVisible: false,
showServerMsgs: true,
showGameMsgs: true,
showChatMsgs: true,
enableDebugMode: false
};
constructor(props: ChatProps) {
super(props);
this.state = {
chatFieldValue: '',
optionsVisible: !!props.inSandbox,
showServerMsgs: true,
showGameMsgs: true,
showChatMsgs: true,
enableDebugMode: !!props.inSandbox
};
}

private chatRef: HTMLDivElement | null = null;

Expand Down Expand Up @@ -209,7 +213,7 @@ export default class Chat extends React.Component<ChatProps, ChatState> {
}

private renderOpenChat(): JSX.Element {
const { compact, header, inGame, messages, roomName, toggleChat } = this.props;
const { compact, header, inGame, inSandbox, messages, roomName, toggleChat } = this.props;
const { optionsVisible, enableDebugMode } = this.state;
const chatTitle = inGame ? 'Chat' : (roomName || 'Lobby');

Expand Down Expand Up @@ -265,7 +269,7 @@ export default class Chat extends React.Component<ChatProps, ChatState> {
style={{ justifyContent: 'space-between', margin: '-12px 0', width: '100%' }}
/>
<FormControlLabel
control={<Switch color="primary" onChange={this.toggleDebugMode} />}
control={<Switch defaultChecked={inSandbox} color="primary" onChange={this.toggleDebugMode} />}
label="Enable debug mode ⚠"
labelPlacement="start"
style={{ justifyContent: 'space-between', margin: '-12px 0', width: '100%' }}
Expand Down
4 changes: 2 additions & 2 deletions src/common/containers/GameAreaContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ export class GameAreaContainer extends React.Component<GameAreaContainerProps, G
}

private get shouldWarnBeforeLeavingPage(): boolean {
const { gameOver, isSpectator } = this.props;
return !gameOver && !isSpectator;
const { gameOver, isPractice, isSandbox, isSpectator, isTutorial } = this.props;
return !gameOver && !isSpectator && !isPractice && !isTutorial && !isSandbox;
}

private urlMatchesGameMode = (mode: string) => this.props.location.pathname.startsWith(urlForGameMode(mode));
Expand Down
2 changes: 1 addition & 1 deletion src/common/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export interface GameState {
executionStackDepth: number
gameFormat: Format
memory: Record<string, unknown>
objectsDestroyedThisTurn: Record<string, HexId> // object id -> last hex id
objectsDestroyedThisTurn: Record<string, [HexId, PlayerColor]> // object id -> (last hex id, player color)
options: GameOptions
player: PlayerColor | 'neither'
players: PerPlayer<PlayerInGameState>
Expand Down
6 changes: 6 additions & 0 deletions src/common/util/browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ export function toggleFlag(flag: string, value?: boolean): void {
saveToLocalStorage(flag, value !== undefined ? value.toString() : isFlagSet(flag) ? 'false' : 'true');
}

export function setFlagIfUnset(flag: string, value: boolean): void {
if (!isFlagSet(flag)) {
toggleFlag(flag, value);
}
}

/** Return the #gameArea element, falling back to the body element if it can't be found. */
export function getGameAreaNode(): HTMLElement {
return document.querySelector('#gameArea') || document.body;
Expand Down
7 changes: 5 additions & 2 deletions src/common/util/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ export function ownerOf(state: w.GameState, object: w.Object): w.PlayerInGameSta
return state.players.blue;
} else if (some(state.players.orange.objectsOnBoard, ['id', object.id])) {
return state.players.orange;
} else if (state.objectsDestroyedThisTurn[object.id]) {
const [, ownerColor] = state.objectsDestroyedThisTurn[object.id];
return state.players[ownerColor];
}
}

Expand Down Expand Up @@ -291,7 +294,7 @@ export function allHexIds(): w.HexId[] {

/** Get the hex id corresponding to the given object, if any. */
export function getHex(state: w.GameState, object: w.Object): w.HexId | undefined {
return findKey(allObjectsOnBoard(state), ['id', object.id]) || state.objectsDestroyedThisTurn[object.id];
return findKey(allObjectsOnBoard(state), ['id', object.id]) || state.objectsDestroyedThisTurn[object.id]?.[0];
}

/** Given a Hex, return all adjacent Hexes on the board. */
Expand Down Expand Up @@ -762,7 +765,7 @@ export function removeObjectFromBoard(state: w.GameState, object: w.Object, hex:
// Unapply any abilities that this object had.
object.abilities.forEach((ability) => unapplyAbility(state, ability));

state.objectsDestroyedThisTurn[object.id] = hex;
state.objectsDestroyedThisTurn[object.id] = [hex, ownerName];

state = applyAbilities(state);
state = checkVictoryConditions(state);
Expand Down
2 changes: 1 addition & 1 deletion src/common/vocabulary/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export function abilities(state: w.GameState): Record<string, w.Returns<Omit<w.P
target.temporaryStatAdjustments = { attack: [], health: [], speed: [], cost: [] };
}

target.temporaryStatAdjustments[att] = target.temporaryStatAdjustments[att]!.concat({
target.temporaryStatAdjustments[att] = (target.temporaryStatAdjustments[att] || []).concat({
aid,
// Convert func to string so that we can serialize this temporaryStatAdjustment if necessary
// (e.g. to reveal a card from the server).
Expand Down
3 changes: 3 additions & 0 deletions src/common/vocabulary/targets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export default function targets(state: w.GameState, currentObject: w.Object | nu
} else {
return { type: 'cards', entries: [state.it] } as w.CardInHandCollection;
}
} else if (state.currentEntryInCollection && g.isObject(state.currentEntryInCollection)) {
// behave properly when iterating over objects
return { type: 'objects', entries: [state.currentEntryInCollection] } as w.ObjectCollection;
} else {
/* istanbul ignore next: this is a fallback that should be rarely hit */
return { type: 'objects', entries: [] } as w.ObjectCollection;
Expand Down
18 changes: 18 additions & 0 deletions test/vocabulary/targets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@ describe('[vocabulary.targets]', () => {
});
});

describe('it', () => {
it('can fall back to the current iteratee when there are no other candidates', () => {
let state = getDefaultState();
state = playObject(state, 'orange', cards.friendlyRiotShieldCard, '3,-1,-2'); // 2/6/3

const loadBalancerCard = action(
"Set each robot's attack equal to its health. Set each robot's speed equal to its health",
[
"(function () { actions['setAttribute'](objectsMatchingConditions('robot', []), 'attack', \"(function () { return attributeValue(targets['it'](), 'health'); })\"); })",
"(function () { actions['setAttribute'](objectsMatchingConditions('robot', []), 'speed', \"(function () { return attributeValue(targets['it'](), 'health'); })\"); })"
]
);
state = playEvent(state, 'orange', loadBalancerCard);
expect(queryObjectAttribute(state, '3,-1,-2', 'attack')).toEqual(6);
expect(queryObjectAttribute(state, '3,-1,-2', 'speed')).toEqual(6);
});
});

describe('that', () => {
// TODO: "Whenever this robot attacks a robot, destroy that robot."

Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载