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
11 changes: 7 additions & 4 deletions src/games/blockilization/client/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import type { CityWire, PreviewAsk, UnitWire } from '../protocol';
import { cam, centreHere, pick, zoom } from './camera';
import { flagsIn, hitAt, type Hit } from './overlay';
import { ask, attackable, cityAt, enemyAt, isNuke, me, myCity, myUnit, store, unitsAt } from './store';
import { closePanels, endTurnAction, explores, front, openCity, platformMenuOpen, selectNextIdle, send, setTipPosition, toggleLens, togglePanel } from './ui';
import { closePanels, endTurnAction, explores, front, openCity, platformMenuOpen, selectNextIdle, send, setTipPosition, toast, toggleLens, togglePanel } from './ui';
import { openPedia, tileArticle } from './pedia';
import { openOverview } from './overview';
import { cycleLens } from './lenses';
import { chargeFrom } from './path';
import { chargeFrom, whyNot } from './path';
import { marchTo } from './march';
import { play } from './sound';
import { closePinMenu, openPinMenu } from './pins';
Expand Down Expand Up @@ -205,8 +205,11 @@ function act(t: number, right: boolean, hit: Hit | null = null, touch = false, s
const unit = sel.id;
ask(`Launch the ${UNITS[sel.type].name} here? Everything in the blast is struck, its land left in fallout, and every civ that knows you will long remember it. It can only fall where everyone it would hit is someone you're at war with.`, 'Launch it', () => send({ t: 'attack', unit, target: t }));
} else send({ t: 'attack', unit: sel.id, target: t });
} else if (UNITS[sel.type]?.domain === 'air') send({ t: 'rebase', unit: sel.id, to: t });
else {
} else if (UNITS[sel.type]?.domain === 'air') {
// (At an enemy it can't strike, out of range or sight: why not, rather than a rebase there that can't be.)
if (enemyAt(t)) toast(whyNot(sel, t));
else send({ t: 'rebase', unit: sel.id, to: t });
} else {
// A melee unit sent at an enemy it can reach this turn charges: next to it, then the attack.
const from = chargeFrom(sel, t);
if (from !== null) {
Expand Down
4 changes: 3 additions & 1 deletion src/games/blockilization/client/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { dangerCost, dangerZones, type Danger } from '../rules/danger';
import { ALL, findWay, neighbours, type Walker } from '../rules/hex';
import { FEATURES, HILLS, RAIL_MOVE, ROAD_MOVE, TERRAINS } from '../rules/terrain';
import { heedsBorders, isGreatPerson, isMilitary, stackKind, UNITS } from '../rules/units';
import { cityAt, enemyAt, me, outOfReach, store } from './store';
import { airWhyNot, cityAt, enemyAt, me, outOfReach, store } from './store';

/**
* The way a unit would go, as this screen can tell (the server works out the real one when it's
Expand Down Expand Up @@ -261,6 +261,8 @@ export function whyNot(u: UnitWire, to: number): string {
const view = store.view;
const type = UNITS[u.type];
if (!view || !type) return "Can't get there";
// (An aircraft doesn't go by a way: it strikes, or rebases.)
if (type.domain === 'air') return airWhyNot(u, to);
const military = soldier(u);
const there = ownThere(u, to);
if (there) return `Your ${unitName(there)} is there (one ${military ? 'soldier' : 'civilian'} to a tile)`;
Expand Down
14 changes: 14 additions & 0 deletions src/games/blockilization/client/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,20 @@ export function outOfReach(u: UnitWire, t: number): string {
return g && distance(g, u.tile, t) <= reachOf(u) ? 'Hills, forest, jungle or mountains block its shot' : `Out of range (${reachOf(u)})`;
}

/**
* Why an aircraft can't strike a tile or rebase to it: an enemy there out of its range, or out of
* sight (it strikes only what its side sees, as the rules' `airTarget` has it); else no base of
* yours there in reach.
*/
export function airWhyNot(u: UnitWire, t: number): string {
const g = store.grid;
if (g && enemyAt(t)) {
if (distance(g, u.tile, t) > reachOf(u)) return `Out of range: it strikes up to ${reachOf(u)} tiles away`;
if (!store.known[t]?.visible) return 'Not in sight: it strikes only what you can see now';
}
return `It rebases only to your cities and ships with room for it, within ${reachOf(u) * 2} tiles`;
}

/**
* Whether a unit could attack a tile from where it stands: a fighting unit, an enemy in sight there,
* in reach; and for a shot past the next tile, a line of sight to it, as the rules' `canFire` has it
Expand Down
13 changes: 10 additions & 3 deletions src/games/blockilization/client/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ export const send = (o: Order) => {
};
/** An order the screen gives for the player (a march's, turn by turn). */
export const sendFor = (o: Order) => client.send('order', o);
/** A word at the top of the screen for a moment, as an order refused gets. */
export function toast(text: string) {
store.toast = { text, until: client.time + 3 };
store.changed++;
}
/** Ask the server what another civ would make of a deal being drawn up (its answer comes as `dealCheck`). */
export const checkDeal = (data: { target: number; items: DealItem[]; key: string }) => client.send('dealCheck', data);
const lobby = (a: LobbyAction) => client.send('lobby', a);
Expand Down Expand Up @@ -1431,7 +1436,7 @@ function renderUnit(): El | null {
: type.abilities?.includes('combat_bonus_aura')
? `${ABILITY_TEXT.combat_bonus_aura} Keep it with your army (it can share a tile with a soldier), out of the enemy's reach.`
: type.domain === 'air'
? `${click(true)} an enemy within ${reachOf(u)} tiles to strike it (they're ringed in red), or one of your cities or ships outlined in blue to rebase there. Fighters and anti-aircraft guns near a target may intercept.${type.class === 'missile' ? ' The missile is spent in its strike.' : ''}`
? `${click(true)} an enemy you can see within ${reachOf(u)} tiles to strike it (they're ringed in red), or one of your cities or ships outlined in blue to rebase there. Fighters and anti-aircraft guns near a target may intercept.${type.class === 'missile' ? ' The missile is spent in its strike.' : ''}`
: type.ranged
? `Enemies in reach are ringed in red: ${touchScreen() ? 'tap one to see how a shot would go, tap it again to fire' : 'point at one to see how a shot would go, click to fire'}.`
: type.strength
Expand Down Expand Up @@ -1569,7 +1574,9 @@ function renderArrival() {
let cls = '';
if (u && t >= 0 && t !== u.tile && store.known[t]) {
const route = attackable(u, t) ? undefined : previewPath(u, t);
if (route === null) [text, cls] = [whyNot(u, t), 'no'];
// (An aircraft goes by no way: it rebases there, or it's told why not.)
if (route === null && u.bases?.includes(t)) text = 'Rebases here: that takes its turn';
else if (route === null) [text, cls] = [whyNot(u, t), 'no'];
else if (route) text = [wayThere(route, u), wallsOnWay(route, u)].filter(Boolean).join(' · ');
}
if (arrival.textContent !== text) {
Expand Down Expand Up @@ -2629,7 +2636,7 @@ function renderTip() {
// (An aircraft rebases, rather than going by a way: where it could, or why not.)
if (sel && t !== sel.tile && !attackable(sel, t) && UNITS[sel.type]?.domain === 'air') {
const base = sel.bases?.includes(t);
bits.push(h(`div.ln.way${base ? '' : '.no'}`, {}, icon(base ? 'plane' : 'close', 13), base ? `${click(true)} to rebase it here` : `It rebases only to your cities and ships with room for it, within ${reachOf(sel) * 2} tiles`));
bits.push(h(`div.ln.way${base ? '' : '.no'}`, {}, icon(base ? 'plane' : 'close', 13), base ? `${click(true)} to rebase it here` : whyNot(sel, t)));
} else if (sel && t !== sel.tile && !attackable(sel, t)) {
const route = previewPath(sel, t);
bits.push(h(`div.ln.way${route ? '' : '.no'}`, {}, icon(route ? 'moves' : 'close', 13), route ? wayThere(route, sel) : whyNot(sel, t)));
Expand Down
Loading